Java.util.Date: try to understand UTC and ET more - java

I live in North Carolina, btw, which is on the East Side. So I compile and run this code and it print out the same thing. The documentation say that java.util.date try to reflect UTC time.
Date utcTime = new Date();
Date estTime = new Date(utcTime.getTime() + TimeZone.getTimeZone("ET").getRawOffset());
DateFormat format = new SimpleDateFormat("dd/MM/yy h:mm a");
System.out.println("UTC: " + format.format(utcTime));
System.out.println("ET: " + format.format(estTime));
And this is what I get
UTC: 11/05/11 11:14 AM
ET: 11/05/11 11:14 AM
But if I go to this website which try to reflect all different time, UTC and ET are different. What did I do wrong here

That's because getRawOffset() is returning 0 - it does that for me for "ET" as well, and in fact TimeZone.getTimeZone("ET") basically returns GMT. I suspect that's not what you meant.
The best Olson time zone name for North Carolina is "America/New_York", I believe.
Note that you shouldn't just add the raw offset of a time zone to a UTC time - you should set the time zone of the formatter instead. A Date value doesn't really know about a time zone... it's always just milliseconds since January 1st 1970 UTC.
So you can use:
import java.text.;
import java.util.;
Date date = new Date();
DateFormat format = new SimpleDateFormat("dd/MM/yy h:mm a zzz");
format.setTimeZone(TimeZone.getTimeZone("America/New_York"));
System.out.println("Eastern: " + format.format(date));
format.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
System.out.println("UTC: " + format.format(date));
Output:
Eastern: 11/05/11 11:30 AM EDT
UTC: 11/05/11 3:30 PM UTC
I'd also recommend that you look into using java.time now - which is much, mnuch better than the java.util classes.

according this post you habe to write TimeZone.getTimeZone("ETS") instead of TimeZone.getTimeZone("ET")

TimeZone.getTimeZone("ET").getRawOffset() is returning 0 this is why

The time zone you're looking for is "EST" or "EDT" (for Daylight time), not "ET". See http://mindprod.com/jgloss/timezone.html.

The proper abbreviation for Eastern Standard Time is "EST", not "ET". It looks like the getRawOffset() method returns 0 if it is passed an unknown time zone.
TimeZone.getTimeZone("EST").getRawOffset()
Also, when you output the utcTime variable, you are not outputting the UTC time. You are outputting EST time because you live in that timezone. From what I understand, the Date class internally stores the time in UTC...but when you format it in order to output it as a human-readable string, it takes the current locale/timezone into account.

Unknowingly, you have introduced two major problems in your code:
Not using the proper timezone name: The two/three/four letter timezone names (e.g. ET, EST, CEST etc.) are error-prone. The proper way of naming a timezone is Region/City e.g. Europe/London. In most cases, the Region is the name of the continent to which the City belongs.
Not using Locale with SimpleDateFormat: A parsing/formatting type e.g. the legacy, SimpleDateFormat or the modern, DateTimeFormatter are Locale-sensitive and therefore you should always use a Locale to avoid surprises. You can check this answer to learn more about it.
Also, note that a java.util.Date object is not a real Date-Time object like the modern Date-Time types; rather, it represents the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT (or UTC). Since it does not hold any format and timezone information, it applies the format, EEE MMM dd HH:mm:ss z yyyy and the JVM's timezone to return the value of Date#toString derived from this milliseconds value. If you need to print the Date-Time in a different format and timezone, you will need to use a SimpleDateFormat with the desired format and the applicable timezone e.g.
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yy hh:mm a zzz", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
System.out.println(sdf.format(date));
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
System.out.println(sdf.format(date));
}
}
A sample output:
05/06/21 08:29 AM EDT
05/06/21 12:29 PM UTC
ONLINE DEMO
java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
A demo using java.time, the modern API:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
Instant now = Instant.now();
System.out.println(now);
ZonedDateTime zdtUTC = now.atZone(ZoneId.of("Etc/UTC"));
System.out.println(zdtUTC);
ZonedDateTime zdtNewYork = now.atZone(ZoneId.of("America/New_York"));
System.out.println(zdtNewYork);
}
}
A sample output:
2021-06-05T12:19:58.092338Z
2021-06-05T12:19:58.092338Z[Etc/UTC]
2021-06-05T08:19:58.092338-04:00[America/New_York]
ONLINE DEMO
Need output string in a different format?
You can use DateTimeFormatter for the output string in a different format e.g.
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
Instant now = Instant.now();
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd/MM/uu hh:mm a zzz", Locale.ENGLISH);
ZonedDateTime zdtUTC = now.atZone(ZoneId.of("Etc/UTC"));
System.out.println(dtf.format(zdtUTC));
ZonedDateTime zdtNewYork = now.atZone(ZoneId.of("America/New_York"));
System.out.println(dtf.format(zdtNewYork));
}
}
A sample output:
05/06/21 12:34 PM UTC
05/06/21 08:34 AM EDT
ONLINE DEMO
Here, you can use yy instead of uu but I prefer u to y.
Learn more about java.time, the modern Date-Time API* from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Related

How to find the timezone id for a time from a string for example "19-Jul-21 1:08:22 PM BST"?

I am trying to make timestamps from a csv of timestamp strings,
eg "21-Mar-21 05:01:26 GMT" and "19-Jul-21 1:08:22 BST"
SimpleDateFormat("dd-MMM-yy hh:mm:ss")
gets the Date.
Is it possible to get the ZoneId from the "GMT" or "BST" strings? (BST being British Summer Time)
or do I need to hardcode a structure mapping one to the other?
java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. Since java.sql.Timestamp extends java.util.Date, it inherits all undesirable things from its parent type. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Solution using java.time, the modern Date-Time API:
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String strDateTime = "21-Mar-21 05:01:26 GMT";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd-MMM-uu HH:mm:ss VV", Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, dtf);
System.out.println(zdt);
// Getting ZoneId
ZoneId zoneId = zdt.getZone();
System.out.println(zoneId);
// If required, get OffsetDateTime from the ZonedDateTime
OffsetDateTime odt = zdt.toOffsetDateTime();
System.out.println(odt);
}
}
Output:
2021-03-21T05:01:26Z[GMT]
GMT
2021-03-21T05:01:26Z
ONLINE DEMO
Check this answer and this answer to learn how to use java.time API with JDBC.
If at all you need java.sql.Timestamp:
For any reason, if you need java.sql.Timestamp, simply get Instant out of the ZonedDateTime and derive the value of Timestamp using Timestamp#from.
Timestamp timestamp = Timestamp.from(zdt.toInstant());
System.out.println(timestamp);
If you just need java.sql.Timestamp, you can do it in the following alternative easier way:
import java.sql.Timestamp;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String strDateTime = "21-Mar-21 05:01:26 GMT";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd-MMM-uu HH:mm:ss VV", Locale.ENGLISH);
Instant instant = Instant.from(dtf.parse(strDateTime));
Timestamp timestamp = Timestamp.from(instant);
System.out.println(timestamp);
}
}
Output:
2021-03-21 05:01:26.0
ONLINE DEMO
Learn more about the modern Date-Time API* from Trail: Date Time.
Update:
This update is based on the following valuable comment by Ole V.V.:
new DateTimeFormatterBuilder().appendPattern("dd-MMM-uu H:mm:ss ").appendZoneText(TextStyle.SHORT, Set.of(ZoneId.of("Europe/London"))).toFormatter(Locale.ENGLISH)
parses 19-Jul-21 1:08:22 BST into
2021-07-19T01:08:22+01:00[Europe/London], which agrees with what the
OP wanted. The mentioned datetime string has 1 digit hour of day, 1,
so we need just one H (which in turn also accepts the 05 from the
other string example).
Demo:
import java.sql.Timestamp;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle;
import java.util.Locale;
import java.util.Set;
public class Main {
public static void main(String[] args) {
String strDateTime = "19-Jul-21 1:08:22 BST";
DateTimeFormatter dtf =
new DateTimeFormatterBuilder()
.appendPattern("dd-MMM-uu H:mm:ss ")
.appendZoneText(TextStyle.SHORT, Set.of(ZoneId.of("Europe/London")))
.toFormatter(Locale.ENGLISH);
Instant instant = Instant.from(dtf.parse(strDateTime));
Timestamp timestamp = Timestamp.from(instant);
System.out.println(timestamp);
}
}
Output:
2021-03-21 05:01:26.0
ONLINE DEMO
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
If you know that GMT and BST are the only time zone abbreviations you will need, and you know for a fact that British Summer Time is the intended interpretation of BST, you can safely use the good answer by Arvind Kumar Avinash.
If there may be more time zone abbreviations in your input and you also know the correct interpretation for those, extending the answer is not difficult. Just pass a larger set of preferred time zones to DateTimeFormatterBuilder.appendZoneText(). For the sake of the example for the following formatter I have specified that BST is British Summer Time, PST is for Pitcairn Standard Time and CST means Cuba Standard Time.
Set<ZoneId> preferredZones = Set.of(ZoneId.of("Europe/London"),
ZoneId.of("Pacific/Pitcairn"), ZoneId.of("America/Havana"));
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.appendPattern("dd-MMM-uu H:mm:ss ")
.appendZoneText(TextStyle.SHORT, preferredZones)
.toFormatter(Locale.ENGLISH);
If you don’t know which time zone abbreviations may turn up in your data or you are not sure of the correct interpretation of each one of them, I think that’s it’s better to give up on the task. Sorry. Those abbreviations are very often ambiguous. Rather than a false result from interpreting the abbreviation wrongly your users will prefer a message stating that you cannot interpret the time zone abbreviation.
Link: Time Zone Abbreviations – Worldwide List.

How to resolve Unparseable date Exception in Java 8 with Date format yyyy-MM-dd hh:mm a

I have a text file from which I am reading and setting transaction POJO class data, to get the difference between start and end time I need to parse the time information in date object.
DateFormat format = new SimpleDateFormat(dateFormat);
System.out.println("Date format in play:"+dateFormat);
Transaction transaction = storageRepositroy.getTransaction(key);
Date start = format.parse(transaction.getStartDate() + " " + transaction.getStartTime());//line no. 29
Date end = format.parse(transaction.getEndDate() + " " + transaction.getEndTime());
I am getting exception while running this code
Exception is
Date format in play:yyyy-MM-dd hh:mm a
java.text.ParseException: Unparseable date: "2020–03–01 03:15 PM"
at java.text.DateFormat.parse(DateFormat.java:366)
at dc.tech.transaction.util.TimeUtil.calculateAverageTime(TimeUtil.java:29)
yyyy-MM-dd hh:mm a is the date format which I am passing to SimleDateFormat constructor. I am unable to understand and debug why I am getting this error.
java.time
I recommend that you use java.time, the modern Java date and time API, for your date and time work.
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("uuuu\u2013MM\u2013dd");
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("hh:mm a", Locale.ENGLISH);
String dateString = "2020–03–01";
String timeString = "03:15 PM";
LocalDate date = LocalDate.parse(dateString, dateFormatter);
LocalTime time = LocalTime.parse(timeString, timeFormatter);
LocalDateTime dateTime = date.atTime(time);
System.out.println(dateTime);
Output:
2020-03-01T15:15
With java.time it is straightforward to combine date and time after parsing, so I prefer to parse them individually.
What went wrong in your code?
Credits go to Ajeetkumar for noticing and reporting in comments: The hyphen in your date string is not a usual minus sign or hyphen with character value 2D hexadecimal (45 decimal), but a en dash with character value 2013 hexadecimal (8211 decimal). So when you specify a usual hyphen in your format pattern string, they don’t match, and parsing fails. Instead I am using a Unicode escape for putting the en dash into the format pattern string. Simply pasting it in there would have worked too (provided that you save your .java file with a character encoding that supports it), but I wanted to make the reader aware that something special was going on here, so I preferred the Unicode escape with \u.
There is another problem with your code: You are not providing any locale for your formatter. So it uses the default locale of your JVM. As long as that locale expects PM, parsing will work. If one day you change your locale setting or run your code on a computer or JVM with a different default locale, parsing will suddenly fail, at you may have a hard time figuring out why. I have specified English locale for parsing the time. Some would prefer doing it for the date too even though technically it isn’t necessary.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Unicode Character 'EN DASH' (U+2013) on FileFormat.info.
I always stick to this mantra: use exactly the same format as your date-time string.
In the solutions given below, I have copied your date-time string into the pattern that I've specified for SimpleDateFormat and DateTimeFormatter and replaced the numbers with the corresponding letters e.g. 2020 with yyyy while keeping the rest of things (symbols, space etc.) intact.
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class Main {
public static void main(String[] args) throws ParseException {
DateFormat sdf = new SimpleDateFormat("yyyy–MM–dd hh:mm a", Locale.ENGLISH);// Make sure to use Locale
String dateTimeString = "2020–03–01 03:15 PM";// The string copied from the exception you have got
Date date = sdf.parse(dateTimeString);
System.out.println(sdf.format(date));
}
}
Output:
2020–03–01 03:15 PM
Note: The date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. I suggest you should stop using them completely and switch to the modern date-time API.
Using the modern date-time API:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy–MM–dd hh:mm a", Locale.ENGLISH);// Make sure to use Locale
String dateTimeString = "2020–03–01 03:15 PM";// The string copied from the exception you have got
System.out.println(LocalDateTime.parse(dateTimeString, dtf));
}
}
Output:
2020-03-01T15:15
Learn more about the modern date-time API at Trail: Date Time.
If you are doing it for your Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

How to convert UTC formatted string to calendar in specific timezone?

I'm trying to convert some string that is in UTC time to a java Calendar object that should be set to GMT-5.
My current UTC string input is this:
UTC date : 20050329174411
I use this code (I detect the 'pattern' as shown below):
DateFormat dateFormat = new SimpleDateFormat(pattern);
Date date = dateFormat.parse(utcDate);
calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT-5"));
calendar.setTime(date);
I then printed the time like this:
calendar.getTime()
And I got this result:
GMT date : Tue Mar 29 17:44:11 EST 2005
I need to support theses date/time string patterns:
FORMAT_UTC4 = "yyyy";
FORMAT_UTC6 = "yyyyMM";
FORMAT_UTC8 = "yyyyMMdd";
FORMAT_UTC10 = "yyyyMMddHH";
FORMAT_UTC12 = "yyyyMMddHHmm";
FORMAT_UTC14 = "yyyyMMddHHmmss";
I would be expecting the time to be set to "12:44:11". I have read a couple of examples and I find date time handling pretty confusing. For me, it's always the same, I get some sort of string formatted UTC and I convert it to GMT-5. I really feel it should be easy!
Ref 1 : How can I get the current date and time in UTC or GMT in Java?
Ref 2 : How to handle calendar TimeZones using Java?
You must set the SimpleDateFormat's time zone to UTC before parsing the date. Else, it uses your default timezone.
And to display the date in the "GMT-5" timezone, you should use another DateFormat, with the timezone set to GMT-5, and format the date with this DateFormat. The toString() method of Date uses your default time zone to transform the date into something readable.
java.time
Note that GMT-5 or timezone offset of -05:00 hours is a fixed offset i.e. independent of the DST and type to represent a date-time with timezone offset is OffsetDateTime.
Demo:
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
public class Main {
public static void main(String[] args) {
Instant instant = Instant.ofEpochMilli(20050329174411L);
OffsetDateTime odt = instant.atOffset(ZoneOffset.of("-05:00"));
// Alternatively
// OffsetDateTime.ofInstant(instant, ZoneOffset.of("-05:00"));
System.out.println(odt);
}
}
Output:
2605-05-15T18:52:54.411-05:00
If you are looking for an automatic adjustment of timezone offset as per the DST, use ZonedDateTime.
Demo:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
Instant instant = Instant.ofEpochMilli(20050329174411L);
ZonedDateTime zdt = instant.atZone(ZoneId.of("America/Chicago"));
// Alternatively
// ZonedDateTime.ofInstant(instant, ZoneId.of("America/Chicago"));
System.out.println(zdt);
}
}
Output:
2605-05-15T18:52:54.411-05:00[America/Chicago]
Learn more about java.time, the modern date-time API* from Trail: Date Time.
If at all you need an object of java.util.Calendar from this object of ZonedDateTime, you can do so as follows:
Calendar calendar = Calendar.getInstance();
calendar.setTime(Date.from(zdt.toInstant()));
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Unable to parse DateTime-string with AM/PM marker

The string I want to format looks like this:
String datetime = "9/1/10 11:34:35 AM"
Following pattern for SimpleDateFormat works:
SimpleDateFormat sdf = SimpleDateFormat("M/d/yy h:mm:ss");
Date d = sdf.parse(datetime);
System.out.println(d);
Output> [Wed Sep 01 11:34:35 CEST 2010]
However I need to parse the AM/PM marker as well, and when I add that to the pattern I receive an exception.
Pattern that doesn't work:
SimpleDateFormat sdf = SimpleDateFormat("M/d/yy h:mm:ss a");
I have tried with this also with same exception:
SimpleDateFormat sdf = SimpleDateFormat("M/d/yy h:mm:ss aa");
Exception:
java.text.ParseException: Unparseable date: "9/1/10 11:34:35 AM"
I have looked through the API at http://download.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html#text but canät seem to find where I do wrong.
Any suggestions?
One possibility is that your default Locale has different symbols for AM/PM. When constructing a date format you should always supply a Locale unless you really want to use the system's default Locale, e.g.:
SimpleDateFormat sdf = new SimpleDateFormat("M/d/yy h:mm:ss a", Locale.US)
Modern answer:
String datetime = "9/1/10 11:34:35 AM";
LocalDateTime dt = LocalDateTime.parse(datetime,
DateTimeFormatter.ofPattern("M/d/yy h:mm:ss a", Locale.ENGLISH));
This produces a LocalDateTime of 2010-09-01T11:34:35. Beware of two digit years, though; DateTimeFormatter will assume 2000 through 2099. For my birthday this would have been incorrect.
We still need to provide the locale. Since AM/PM markers are hardly used in practice in other locales than English, I considered Locale.ENGLISH a fairly safe bet. Please substitute your own.
The other answers were fine answers in 2010 and 2011. Already in 2014 the above was valid and I would have preferred it.
I am taking an example of date given below and print the formatted date into 24-hour format if suits your requirement.
String inputdate="9/1/10 11:34:35 AM";
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("dd/MM/yy hh:mm:ss aa",Locale.getDefault());
try {
System.out.println(""+new SimpleDateFormat("dd/MM/yy HH:mm:ss",Locale.getDefault()).format(simpleDateFormat.parse(inputdate)));
} catch (ParseException e) {
e.printStackTrace();
}
If you still have any query, Please respond. Thanks.
java.time
You can build a case-insensitive parser using DateTimeFormatterBuilder. Since a date-time parsing/formatting type (e.g. DateTimeFormatter, SimpleDateFormat etc.) is Locale-sensitive, you should always use a Locale with such a type. I've used Locale.ENGLISH because your date-time string has AM/PM marker in English.
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Locale;
import java.util.stream.Stream;
public class Main {
public static void main(String args[]) {
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("M/d/uu H:m:s a")
.toFormatter(Locale.ENGLISH);
//Test
Stream.of(
"9/1/10 11:34:35 AM",
"9/1/10 11:34:35 am",
"09/1/10 11:34:35 AM",
"9/01/10 11:34:35 Am"
).forEach(s -> System.out.println(LocalDateTime.parse(s, dtf)));;
}
}
Output:
2010-09-01T11:34:35
2010-09-01T11:34:35
2010-09-01T11:34:35
2010-09-01T11:34:35
Learn more about the the modern date-time API* from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
If you are working with FreeMarker for Java and pop on this issue use below code. I had this problem, my locale set AM/PM as DE. Not sure why...
<#setting locale="en_US">
Just a note about Locale:
the symbols used for AM/PM depend on Locale!
This affects parsing strings, eventually causing errors if the used AM/PM field does not match the predefined symbols. (obviously also affects formatting)
java.time.format.DateTimeFormatter and java.text.SimpleDateFormat accept an optional Locale when being created. If none is given. the systems default one is used.
Warning: using DateTimeFormatter the case of the AM/PM flag is also relevant when parsing, at least for some locales.
As an example, the Indian Locale requires the AM/PM flag being lowercase (am, pm), while some other locales (ROOT, ITALY, US, GERMANY) only accept uppercase AM/PM.
This throws DateTimeParseException: Text '2021-03-31 10:15:30 AM +05:30' could not be parsed at index 20
ZonedDateTime.parse("2021-03-31 10:15:30 AM +05:30",
DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss a Z",
new Locale("en", "IN")))
This results in 2021-03-31T10:15:30+05:30
ZonedDateTime.parse("2021-03-31 10:15:30 am +05:30",
DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss a Z",
new Locale("en", "IN")))
Using Locale.US, Locale.GERMANY or Locale.ROOT, the results are inverted.
Note: case of AM/PM does not matter when parsing with SimpleDateFormat (I am not recommending its use, I prefer DateTimeFormatter)

Generating UTC Time in java

I want to get the UTC time for 01/01/2100 in Java to '2100-01-01 00:00:00'. I am getting "2100-01-01 00:08:00". Any idea, how to correct this.
public Date getFinalTime() {
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
Date finalTime = null;
try
{
finalTime = df.parse("01/01/2100");
} catch (ParseException e)
{
e.printStackTrace();
}
calendar.setTime(finalTime);
return calendar.getTime();
}
You need to specify the time zone for the SimpleDateFormat as well - currently that's parsing midnight local time which is ending up as 8am UTC.
TimeZone utc = TimeZone.getTimeZone("UTC");
Calendar calendar = Calendar.getInstance(utc);
DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
df.setTimeZone(utc);
Date finalTime = null;
try
{
finalTime = df.parse("01/01/2100");
} catch (ParseException e)
{
e.printStackTrace();
}
calendar.setTime(finalTime);
As ever though, I would personally recommend using Joda Time which is far more capable in general. I'd be happy to translate your example into Joda Time if you want.
Additionally, I see you're returning calendar.getTime() - that's just the same as returning finalTime as soon as you've computed it.
Finally, just catching a ParseException and carrying on as if it didn't happen is a very bad idea. I'm hoping this is just sample code and it doesn't reflect your real method. Likewise I'm assuming that really you'll be parsing some other text - if you're not, then as Eyal said, you should just call methods on Calendar directly. (Or, again, use Joda Time.)
You need to set the time zone of the SimpleDateFormat object as well, otherwise it assumes the default time zone.
Anyway, it seems like using only a Calendar is enough in your case. Use its setters to set the right values for all fields (year, month, day, hour, etc), and then retrieve the time.
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Also, quoted below is a notice at the Home Page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time, the modern API:
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String strDate = "01/01/2100";
DateTimeFormatter dtfInput = DateTimeFormatter.ofPattern("d/M/u", Locale.ENGLISH);
ZonedDateTime zdt = LocalDate.parse(strDate, dtfInput)
.atStartOfDay(ZoneId.of("Etc/UTC"));
// Default format
System.out.println(zdt);
// Getting and displaying LocalDateTime
LocalDateTime ldt = zdt.toLocalDateTime();
System.out.println(ldt);
// A custom format
DateTimeFormatter dtfOutput = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss", Locale.ENGLISH);
// Alternatively dtfOutput.format(ldt);
String formatted = dtfOutput.format(zdt);
System.out.println(formatted);
// Converting to some other types
OffsetDateTime odt = zdt.toOffsetDateTime();
Instant instant = zdt.toInstant();
System.out.println(odt);
System.out.println(instant);
}
}
Output:
2100-01-01T00:00Z[Etc/UTC]
2100-01-01T00:00
2100-01-01 00:00:00
2100-01-01T00:00Z
2100-01-01T00:00:00Z
ONLINE DEMO
The Z in the output is the timezone designator for zero-timezone offset. It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).
Note: The Date-Time without timezone name or timezone offset should be represented by LocalDateTime (which is used for events that are normally not represented with timezone information). In this sense, LocalDateTime is useless in this case and you should use ZonedDateTime itself or Instant or OffsetDateTime. I recommend you also check this answer and this answer if you are dealing with JDBC.
Learn more about java.time, the modern Date-Time API* from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
java.time
Like Arvind Kumar Avinash I very clearly recommend that you use java.time, the modern Java date and time API, for your date and time work. If what you want is a fixed (constant) date and time, use OffsetDateTime.of().
OffsetDateTime finalTime = OffsetDateTime.of(2100, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC);
System.out.println(finalTime);
Output:
2100-01-01T00:00Z
The trailing Z means UTC.
Tutorial link
Oracle tutorial: Date Time explaining how to use java.time.
TimeZone utc = TimeZone.getTimeZone("UTC");
Calendar calendar = Calendar.getInstance(utc);
DateFormat dateformat = new SimpleDateFormat("dd/MM/yyyy");
dateformat.setTimeZone(utc);
Timezone needs to be set.

Categories