I am trying to convert IST to UTC epoch in Java
But instead of subtracting 5.30 hours from IST, it adds 5.30 in IST
public static long convertDateToEpochFormat(String date) {
Date convertedDate = null;
try {
LOGGER.info(date);
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
LOGGER.info(date);
convertedDate = formatter.parse(date);
LOGGER.info(convertedDate);
} catch (ParseException e) {
e.printStackTrace();
}
return convertedDate.getTime() / 1000L;
}
The log statements I obtained is :
2017-01-01 00:00:00
2017-01-01 00:00:00
Sun Jan 01 05:30:00 IST 2017
It should ideally be Dec 31 18:30:00 because of UTC conversion.
Can anyone tell me whats wrong ?
tl;dr
Why does util.Date forwards the date instead of subtracting it?
Because India time is ahead of UTC, not behind.
Instant.parse(
"2017-01-01 00:00:00".replace( " " , "T" ) + "Z"
).atZone(
ZoneId.of( "Asia/Kolkata" )
).toString()
2017-01-01T05:30+05:30[Asia/Kolkata]
Using java.time
You are using troublesome old date-time classes that are now legacy, supplanted by the java.time classes.
ISO 8601
Your input string is almost in standard ISO 8601 format. To comply fully, replace that SPACE in the middle with a T. The java.time classes use standard formats when parsing/generating strings. So no need to specify a formatting pattern.
String input = "2017-01-01 00:00:00".replace( " " , "T" ) ;
If that input is meant to represent a moment in UTC, append a Z, short for Zulu, means UTC.
String input = "2017-01-01 00:00:00".replace( " " , "T" ) + "Z" ; // Assuming this input was intended to be in UTC.
2017-01-01T00:00:00Z
When possible, just use the ISO 8601 formats in the first place when serializing date-time values to strings.
Instant
Parse that input string as an Instant, a moment on the timeline in UTC with a resolution of nanoseconds.
Instant instant = Instant.parse( input ) ;
instant.toString(): 2017-01-01T00:00:00Z
ZonedDateTime
You seem to want this value adjusted into India time. Apply a ZoneId to get a ZonedDateTime.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
zdt.toString(): 2017-01-01T05:30+05:30[Asia/Kolkata]
See this code run live at IdeOne.com.
India time is ahead of UTC
Your Question expects the India time to go backwards, behind the UTC value. This makes no sense. India time is ahead of UTC, not behind UTC. The Americas have time zones behind UTC as they lay westward. East of the Prime Meridian in Greenwich are offsets ahead of UTC. In modern times, ISO 8601 and most other protocols mark such offsets with a plus sign: +05:30. Note that some old protocols did the opposite (used a negative sign).
Midnight UTC = 5:30 AM India
So midnight in UTC, 00:00:00 at the Prime Meridian, is simultaneously five-thirty in the morning in India.
So all three of these represent the same simultaneous moment, the same point in the timeline:
2017-01-01T00:00:00Z
2017-01-01T05:30+05:30[Asia/Kolkata]
2016-12-31T16:00-08:00[America/Los_Angeles]
Avoid count-from-epoch
Do not handle time as an integer count from epoch as you are doing by returning a long from your method as seen in the Question. In your Java code pass around date-time values using date-time objects, java.time objects specifically. When passing date-time values outside your Java code, serialize to strings using the practical ISO 8601 formats.
Relying on an integer count-from-epoch values is confusing, difficult to debug, impossible to read by humans, and will lead to frustration and errors (even worse: unobserved errors).
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
The answer by Basil Bourque is not only correct, it is also very informative. I have already upvoted it. I’ll try just a little bit of a different angle.
As I understand your question, your date-time string 2017-01-01 00:00:00 should be interpreted in IST, AKA Asia/Kolkata time, and you want to convert it to seconds (not milliseconds) since the epoch. And you are asking why you are getting an incorrect result.
I think the answer is rather banal: When the date-time string is in India time, you should not set UTC time on the formatter you use for parsing it. This is sure to get an incorrect result (if you were to format the date-time into UTC, you would do well in setting UTC as time zone on the formatter used for formatting, but this is a different story).
I agree with Basil Bourque that you should avoid the outdated classes Date and SimpleDateFormat. So here’s my suggestion (assuming you do need epoch seconds and cannot use an Instant as Basil Bourque recommends).
private static DateTimeFormatter parseFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
public static long convertDateToEpochFormat(String date) {
return LocalDateTime.parse(date, parseFormatter)
.atZone(ZoneId.of("Asia/Kolkata"))
.toInstant()
.getEpochSecond();
}
This will convert your example string into an instant of 2016-12-31T18:30:00Z and return 1483209000. Please check for yourself that it is correct.
I have been assuming all the way that by IST you meant Indian Standard Time. Please be aware that three and four letter time zone abbreviations are ambiguous. For example, my JVM thinks that IST means Israel Standard Time. If you intended the same, please substitute Asia/Jerusalem for Asia/Kolkata. If you meant Irish Standard Time (another recognized/semi-official interpretation), please use Europe/Dublin. You will of course get different output in each case.
Related
I am trying to parse the String to date. String having date format as
"dd-MMM-yyyy Z" and String having value "12-DEC-2018 ET". Its giving the error
java.text.ParseException: Unparseable date: "12-DEC-2018 ET".
The same code is working for String having value "12-DEC-2018 IST".
below is the code snippet:
public static void main(String[] args) throws ParseException {
String dateInputIST ="12-DEC-2018 IST";
String dateInputET ="12-DEC-2018 ET";
SimpleDateFormat sdfmt1 = new SimpleDateFormat("dd-MMM-yyyy Z");
SimpleDateFormat sdfmt2= new SimpleDateFormat("dd/MM/yyyy");
Date dDate = sdfmt1.parse( dateInputIST );
String strOutput = sdfmt2.format( dDate );
System.out.println(strOutput);
Date etDate = sdfmt1.parse(dateInputET);
strOutput = sdfmt2.format(etDate);
System.out.println(strOutput);
}
Could someone please help. I needed to parse the time in any timezone.
Thanks,
Navin
Change
String dateInputET ="12-DEC-2018 ET";
to
String dateInputET ="12-DEC-2018 EDT";
'ET' is not a recognized time zone.
Pseudo-zones
ET, EST, and IST are not actually time zones. Those 2-4 letter pseudo-zones are not standardized and are not even unique! For example, IST can mean India Standard Time, Ireland Standard Time, Iceland Standard Time, and more.
Real time zone names take the format of Continent/Region such as Africa/Tunis.
Date & zone, separately
Date with time zone has no real meaning.
Handle the date as a LocalDate object.
String input = "12-DEC-2018"
DayeTimeFormatter f = DateTimeFormatter.ofPattern( "dd-MM-uuuu" , Locale.US ) ;
LocalDate ld = LocalDate.parse( input , f ) ;
Handle your desired time zone separately, as a ZoneId object.
ZoneId zNewYork = ZoneId.of( "America/New_York" ) ;
To combine, determine the first moment of the day.
ZonedDateTime zdtNewYork = ld.atStartOfDay( z ) ;
Generate text representing that moment in standard ISO 8601 format extended to append the name of the time zone in square brackets.
To see that same moment in UTC, extract a Instant.
Instant instant = zdtNewYork.toInstant() ;
Adjust into another zone.
ZonedDateTime zdtKolkata = instant.atZone( ZoneId.of( "Asia/Kolkata" ) ) ;
To focus on the date only, get a LocalDate for the day of that same moment when viewed through the lens of the wall-clock time used in India.
LocalDate ldKolkata = zdtKolkata.toLocalDate() ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
java.time
DateTimeFormatter dateZoneFormatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("dd-MMM-uuuu v")
.toFormatter(Locale.ENGLISH);
String dateInputIST ="12-DEC-2018 IST";
String dateInputET ="12-DEC-2018 ET";
TemporalAccessor parsed = dateZoneFormatter.parse(dateInputIST);
System.out.println("Date: " + LocalDate.from(parsed) + " Time zone: " + ZoneId.from(parsed));
parsed = dateZoneFormatter.parse(dateInputET);
System.out.println("Date: " + LocalDate.from(parsed) + " Time zone: " + ZoneId.from(parsed));
On my computer the output from this snippet was:
Date: 2018-12-12 Time zone: Atlantic/Reykjavik
Date: 2018-12-12 Time zone: America/New_York
Format pattern letter v is for the generic time-zone name, that is, the name that is the same all year regardless of summer time (DST), for example Eastern Time or short ET.
If you want to control the interpretation of ambiguous time zone abbreviations (of which there are a lot), you may use the two-arg appendGenericZoneText(TextStyle, Set<ZoneId>) where the second argument contains the preferred zones. Still better if there is a way for you to avoid relying on time zone abbreviations altogether since, as I said, they are very often ambiguous.
I am not sure what sense a date with a time zone makes, though.
As an additional point, always specify locale for your formatters so they will also work if the default locale is changed or one day your program runs in a JVM with a different default locale.
Avoid SimpleDateFormat and Date
I don’t think SimpleDateFormat will be able to parse your string. It’s just the same since that class is already long outdated and is renowned for being troublesome, so you should never want to use it anyway.
I am trying to use mongodb to fetch some records with date fields, sample records are shown below, and want convert date field which has been parsed using jayway jsonpath to java.util.Date long integer. long integer converted does not match with the original one. Please help.
Sample records in tester collection:
{
"_id" : ObjectId("5b3fe6f91e618afb473dc644"),
"dateField" : ISODate("2018-07-06T15:46:55.819Z")
}
The Java code for getting records using jongo is as follows :
List<Tester> list= jongo.runCommand("{aggregate : 'tester',pipeline:[],cursor : {batchSize :10}}")
.field("cursor")
.as(Tester.class);
for(Tester t : list)
{
System.out.println("dateField test: : : : "+t.getDateField()+" : : : : "+t.getDateField().getTime());
// Output is perfectly fine : dateField test: : : : Fri Jul 06 21:16:55 IST 2018 : : : : 1530892015819
Gson gson = new Gson();
String str = gson.toJson(t);
DocumentContext docCtx = JsonPath.parse(str);
JsonPath jsonPath = JsonPath.compile("$.dateField");
Object obj = docCtx.read(jsonPath);
System.out.println(obj);
//After parsing with jsonPath the date is retained - Jul 6, 2018 9:16:55 PM
SimpleDateFormat format = new SimpleDateFormat("MMM dd, yyyy hh:mm:ss aaa");
Date d = format.parse(obj.toString());
System.out.println(d + " : : : " + d.getTime());
//Fri Jul 06 21:16:55 IST 2018 : : : 1530892015000 - Time is not retained
}
Expected :
t.getDateField().getTime() ==== d.getTime()
Please help
Regards
Kris
tl;dr
Your formatting pattern omits the fractional seconds, so no milliseconds appear in the output.
You are using obsolete date-time classes. Use java.time instead.
Example:
Instant // Represent a moment in UTC, with a resolution as fine as nanoseconds.
.parse( "2018-07-06T15:46:55.819Z" ) // Parse a string in standard ISO 8601 format. The `Z` on the end means UTC, pronounced “Zulu”.
.atZone( ZoneId.of( "Asia/Kolkata" ) ) // Adjust from UTC to a desired time zone. Same moment, same point on the timeline, different wall-clock time. Returns a `ZonedDateTime` object.
.toString() // Generate a String in standard ISO 8601 format. Represents the moment in our `ZonedDateTime` object.
Convert from legacy java.util.Date class to modern java.time.Instant, and back again. Example nonsense code:
java.util.Date.from( // Convert from modern `Instant` to legacy `Date`.
myJavaUtilDate.toInstant() // Convert from legacy `Date` to modern `Instant`.
)
java.time
You are using terribly troublesome old date-time classes: Date & SimpleDateFormat. These were supplanted years ago by the modern java.time classes.
Your input 2018-07-06T15:46:55.819Z is in standard ISO 8601 format. The java.time classes use the ISO 8601 formats by default when parsing or generating strings. So no need to specify a formatting pattern.
The Z on the end is pronounced Zulu and means UTC. The Instant class represents a moment in UTC.
Instant instant = Instant.parse( "2018-07-06T15:46:55.819Z" ) ;
Generate an output string in ISO 8601 format.
String output = instant.toString() ;
2018-07-06T15:46:55.819Z
Your code ignores the crucial issue of time zone. Rather than rely implicitly on the JVM’s current default time zone, be explicit with a ZoneId even if that is ZoneId.systemDefault().
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!). For example, your IST could mean Irish Standard Time, India Standard Time, Iran Standard Time, or something else.
After adjusting from UTC to a specific time zone, we still have the same moment, the same point on the timeline. Only the wall-clock time is different.
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ; // Or `ZoneId.systemDefault()`.
ZonedDateTime zdt = instant.atZone( z ) ; // Adjust from UTC to a specific time zone.
Generate an output string in ISO 8601 format extended to append the name of the time zone in square brackets.
String output = zdt.toString() ;
2018-07-06T21:16:55.819+05:30[Asia/Kolkata]
Notice your fractional second (milliseconds) is still intact.
Converting
Perhaps you must interface with an java.util.Date (your Question is not clear), because of old code not yet updated to support java.time.
You will find convenient conversion methods, new methods added to the old classes.
Going from java.util.Date to java.time.Instant.
Instant myInstant = myJavaUtilDate.toInstant() ;
Proceed as shown above. Adjust into your desired time zone, and generate a String.
Going the other direction, from the modern Instant class to the legacy class Date.
java.util.Date myDate = java.util.Date.from( myInstant ) ;
Immutable objects
The java.time classes are designed to be thread-safe, and use the immutable objects pattern. Notice how the code above produces fresh objects based on the original’s values, rather than altering (“mutating”) the original.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
new SimpleDateFormat("MMM dd, yyyy hh:mm:ss aaa");
You are discarding the milliseconds part of the input, which results in exactly the difference you see. Use this instead:
new SimpleDateFormat("MMM dd, yyyy hh:mm:ss.SSS aaa");
^^^^
I'm sending date from the Angular app as String to server and converting to java Date object to store in the database.
Also sending timeZoneOffset from UI to use the client's time zone while converting. (After googling I found this approach to get the proper result based on the user location)
Written the following code to convert:
public static void main(String args[]) throws ParseException {
String inputDate = "04/05/2018"; // This date coming from UI
int timeZoneOffset = -330; // This offset coming from UI
// (new Date().getTimeZoneOffset())
getDate(inputDate, timeZoneOffset);
}
public static Date getDate(String inputDate, int timeZoneOffset)
throws ParseException {
SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
ZoneOffset zoneOffset = ZoneOffset.ofTotalSeconds(-timeZoneOffset * 60);
System.out.println("Default time zone: " + TimeZone.getDefault().getID());
TimeZone timeZone = TimeZone.getTimeZone(zoneOffset);
System.out.println("Time zone from offset: " + timeZone.getID());
dateFormat.setTimeZone(timeZone);
Date date = dateFormat.parse(inputDate);
System.out.println("Converted date: " + date);
return date;
}
Expected output:
Default time zone: America/New_York
Time zone from offset: GMT+05:30
Converted date: Thu April 5 00:00:00 IST 2018
Actual result in server:
Default time zone: America/New_York
Time zone from offset: GMT+05:30
Converted date: Wed April 4 14:30:00 EDT 2018
Why is the date decreasing to one day even I set the users time zone? I'm new to Date and Time related concepts and I googled a couple of times didn't find answer, could someone please help on this.
Thanks in advance
The Answer by Godfrey is correct.
tl;dr
LocalDate.parse(
"04/05/2018" ,
DateTimeFormatter.ofPattern( "MM/dd/uuuu" )
)
.atStartOfDay(
ZoneId.of( "Asia/Kolkata" )
)
.toString()
2018-04-05T00:00+05:30[Asia/Kolkata]
For storage in your database, use UTC.
When a new day starts in India, the date at UTC is still “yesterday”, so April 4th rather than April 5th. Same moment, same point on the timeline, different wall-clock time.
LocalDate.parse(
"04/05/2018" ,
DateTimeFormatter.ofPattern( "MM/dd/uuuu" )
)
.atStartOfDay(
ZoneId.of( "Asia/Kolkata" )
)
.toInstant()
2018-04-04T18:30:00Z
java.time
You are using terrible old date-time classes that have proven to be poorly designed, confusing, and troublesome. They are now supplanted by the java.time classes.
Avoid legacy date-time classes entirely
ZoneOffset zoneOffset = ZoneOffset.ofTotalSeconds(-timeZoneOffset * 60);
…
TimeZone timeZone = TimeZone.getTimeZone(zoneOffset);
You are mixing the modern classes (ZoneOffset) with the troublesome legacy classes (TimeZone). Do not mix the modern classes with the legacy classes. Forget all about the old classes including Date, Calendar, and SimpleDateFormat. The java.time classes are designed to entirely supplant the legacy classes.
Instead of TimeZone, use ZoneId (and ZoneOffset).
LocalDate
Parse your input string as a LocalDate. The LocalDate class represents a date-only value without time-of-day and without time zone.
String input = "04/05/2018" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "MM/dd/uuuu" ) ;
LocalDate ld = LocalDate.parse( input , f ) ;
Offset versus Time Zone
int timeZoneOffset = -330;
An offset-from-UTC is not a time zone. An offset is simply a number of hours, minutes, and seconds of displacement from UTC. Your choice of variable name indicates possible confusion on this point.
ZoneOffset offset = ZoneOffset.of( -3 , 30 ) ;
A time zone is a history of past, present, and future changes in offset used by the people of a particular region. So a time zone is always preferable to an offset.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ; // India time zone. Currently uses offset of +05:30 (five and a half hours ahead of UTC).
First moment of the day
You seem to be aiming for the first moment of that date in that zone. Let java.time determine that first-moment-of-the-day. Do not assume that time is 00:00:00. In some zones on some dates, the day may start at another time such as 01:00:00.
ZonedDateTime zdt = ld.atStartOfDay( z ) ; // Determine the first moment of the day on this date in this zone. Not always 00:00:00.
As an example of why you should be using time zones rather than mere offset-from-UTC, look at your example data of -330 which I might easily misinterpret to be three and a half hours behind UTC. This offset is currently only used in the zone America/St_Johns, and only used there for part of the year. So if you applied an offset of -03:30 to a date in the wrong part of the year, your results would be invalid yet go undetected.
Using offset (not recommended)
But your example lacks time zone, so let’s go with offset-from-UTC rather than zone.
Your use of an int integer number to represent an offset-from-UTC is a poor choice of types. First of all, it is ambiguous. That -330 might be interpreted to be a clumsy attempt at -03:30 offset of three and a half hours behind schedule. Secondly, it makes parsing trickier than need be. Thirdly, as a number of minutes, it ignores the possibility of an offset with seconds. Fourthly, you use a negative number for an offset ahead of UTC (apparently) despite common usage and standard usage being the opposite. Lastly, it ignores the clear standard set by ISO 8601 for representing offsets as text: ±HH:MM:SS (and variations). By the way, the padding zero is optional in the standard, but I recommend always including because various libraries and protocols expect it.
Your intent appears to be a number of minutes intended by the integer number.
long seconds =( TimeUnit.MINUTES.toSeconds( - 330 ) * -1 ); // Multiply by negative one to flip the sign to standard ISO 8601 usage, where `+` means “ahead* of UTC and `-` means *behind* UTC.
seconds: 19800
ZoneOffset offset = ZoneOffset.ofTotalSeconds( ( int ) seconds );
offset.toString(): +05:30
Last step: get the first moment of the day in this offset. Caveat: We do not know for certain if this offset is valid on this date, as we lack a time zone.
Convert from the returned ZonedDateTime to an OffsetDateTime. As discussed above, determining first moment of day should always be done with a time zone, and thereby get a ZonedDateTime. We are violating that sensible practice to use an offset, but using the returned ZonedDateTime object would be misleading as ours would lack a true time zone, and have only a mere offset. So the OffsetDateTime class makes our intentions clear and our code more self-documenting.
OffsetDateTime odt = ld.atStartOfDay( offset ).toOffsetDateTime();
Again, this approach using offset is not recommending, as you should be instead gathering a time zone name from the user as input rather than an offset.
UTC
Generally best to store moments in UTC.
Extract a Instant from your OffsetDateTime or ZonedDateTime to get the same moment as UTC.
Instant instant = zdt.toInstant() ;
2018-04-04T18:30:00Z
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
It's not decreasing by one day, it is decreasing by 11.5 hours. That happens to be the time difference between GMT+05:30 and "America/New_York", which is GMT-04:30 or GMT-05:30 (depending on time of year).
GMT+05:30 is somewhere in India, I think, since that is about the only place to use a 30 minute offset rather than a whole hour. When it is April 5th in India, it is still April 4th in New York.
The problem may be you aren't getting a time from the client, so it will assume midnight. If you are doing time zone conversion, it is best to include the actual time.
Why does java.util.Date object show date & time with respect to a timezone when in actuality, java.util.Date represents an instant on the time-line, not a "date"?
The actual data stored within the object is a long count of milliseconds since 1970-01-01T00:00Z (midnight at the start of 1970 GMT/UTC).
Also in docs, A java.util.Date instance has no concept of time-zone.
If so is the case, why does this snippet print date specifying timezone.
public static void main(String[] args) {
Date date = new Date();
System.out.println(date);
}
Output : Wed Mar 22 14:58:56 IST 2017
Why is it showing specific timezone in the output? I understand the SOP implements toString() internally. Does toString() effect the timezone?
Just follow the javadoc, as it says:
public String toString()
Converts this Date object to a String of the form:
dow mon dd hh:mm:ss zzz yyyy
zzz is the time zone (and may reflect daylight saving time).
And when you dive into the source code, that this toString() implementation will at some point use TimeZone.getDefault()
( or to be precise: getDefaultRef()). In other words: the default implementation pulls in the "default" timezone of your JVM.
tl;dr
Current moment in UTC.
Instant.now() // Capture current moment in UTC.
.toString() // Generate String in standard ISO 8601 format.
2018-01-23T01:23:45.677340Z
Current moment in India time zone.
ZonedDateTime.now(
ZoneId.of( "Asia/Kolkata" )
).toString() // Generate string in format wisely extended from ISO 8601 standard, adding the time zone name in square brackets.
2018-01-23T06:53:45.677340+05:30[Asia/Kolkata]
Avoid legacy date-time classes
Why does java.util.Date object show date & time with respect to a timezone when in actuality, java.util.Date represents an instant on the time-line, not a "date"?
Because the java.util.Date and related classes (Calendar, SimpleDateFormat, and such) are poorly-designed. While a valiant effort at tackling the tricky subject of date-time handling, they fall short of the goal. They are riddled with poor design choices. You should avoid them, as they are now supplanted by the java.time classes, an enormous improvement.
Specifically to answer your question: The toString method of Date dynamically applies the JVM’s current default time zone while generating a String. So while the Date object itself represents a moment in UTC, the toString creates the false impression that it carries the displayed time zone.
Even worse, there is a time zone buried inside the Date object. That zone is used internally, yet is irrelevant to our discussion here. Confusing? Yes, yet another reason to avoid this class.
A java.util.Date instance has no concept of time-zone.
Not true. A Date represents a specific moment, a point on the timeline, with a resolution of milliseconds, in UTC. As you mention, it is defined as a count of milliseconds since the first moment of 1970 in UTC.
java.time
The java.time classes separate clearly the concepts of UTC, zoned, and unzoned values.
The java.time.Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction). This class replaces java.util.Date.
Instant instant = Instant.now() ; // Capture current moment in UTC.
Apply a time zone (ZoneId object) to an Instant and you get a ZonedDateTime object. That class replaces the java.util.Calendar class.
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = instant.atZone( z ) ; // Same simultaneous moment as `instant`, but different wall-clock time.
If a value has only an offset-from-UTC but not a full time zone, use the OffsetDateTime class.
For a date only, without time-of-day and without time zone, use the LocalDate class. This class replaces the java.sql.Date class. Ditto for LocalTime replacing java.sql.Time.
LocalDate xmasDate2018 = LocalDate.of( 2018 , Month.DECEMBER , 25 ) ;
If the zone or offset are unknown or indeterminate, such as "Christmas starts at stroke of midnight on December 25, 2018", use the LocalDateTime class. This class does not represent an actual moment, a specific point on the timeline. This class lacks any concept of time zone or offset. So it can only represent potential moments along a range of about 26-27 hours.
LocalDateTime xmasEverywhere2018 = LocalDateTime.of( xmasDate2018 , LocalTime.MIN ) ;
Or…
LocalDateTime xmasEverywhere2018 = LocalDateTime.of( 2018 , Month.DECEMBER , 25 , 0 , 0 , 0 , 0 ) ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
With a JDBC driver complying with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings or java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
It does have a concept of time zone, but it is always UTC. When it prints the date therefore there is no problem converting it to the time zone of your computer.
This question already has answers here:
Epoch is not epoch if do a new Date(0L). Why?
(4 answers)
Closed 5 years ago.
The Java doc describe that the constructor Date(long date) constructs a Date object using the given milliseconds time value since January 1, 1970, 00:00:00 GMT
When I did new Date(0), the date is Jan 01 01:00:00 CET 1970
I don't know why it begin with 01h
It's show 1AM because you're an hour ahead of GMT. A date instance is simply a counter of the number of milliseconds since 00:00:00 1970 GMT. Since your an hour ahead, when the epoch occurred it was actually 1AM your time.
The Date instance simply formats its toString() method to use your system's timezone. If you want to print out a date using a different zone, use a DateFormat instance.
This is because you are showing the date in the European timezone (CET) the unix time (the milliseconds you are giving the Date object) use GMT.
tl;dr
Instant.now() // Current moment in UTC.
Details
The Answer by Nichols is correct but outdated.
Your own time zone was an hour ahead of UTC on that date, so midnight in UTC is 1 AM in your zone.
Nowadays you should be using java.time classes such as Instant instead of Date.
Avoid legacy classes
Avoid the troublesome old date-time classes now supplanted by the java.time classes.
Among the many problems of the legacy classes was the poor design choice to have the toString method dynamically apply the JVM’s current default time zone while generating the string representing the object’s value. A Date actually represents a moment in UTC. Avoid awkward class entirely. If necessary, convert between the legacy and modern classes via new methods added to the old classes.
Instant for UTC
The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
Instant instant = Instant.now() ; // Current moment in UTC.
instant.toString(): 2018-02-11T21:07:02.315283Z
If you want the epoch reference moment used by the java.time classes, the first moment of 1970 in UTC, use the predefined constant: Instant.EPOCH.
Instant.EPOCH.toString(): 1970-01-01T00:00:00Z
OffsetDateTime
If you need more flexibility, such as generating strings in other formatting, convert the Instant object to a OffsetDateTime using the constant ZoneOffset.UTC.
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
ISO 8601
When exchanging date-time values as text, use the standard ISO 8601 formats. They were designed to be easy to parse by machine while also being easy to read by humans across various cultures.
The java.time classes use the standard ISO 8601 formats by default when generating/parsing strings. So no need to specify a formatting pattern.
Time zone, ZonedDateTime
If you want to see the same simultaneous moment through the lens of the wall-clock time used by the people of another region, apply a time zone (ZoneId) to get a ZonedDateTime object.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST or CET as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "Europe/Paris" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
zdt.toString(): 2018-02-11T22:07:02.315283+01:00[Europe/Paris]
Let's look at the java.time epoch reference moment through the same time zone.
ZonedDateTime zdtEpochParis = Instant.EPOCH.atZone( z ) ;
zdtEpochParis.toString(): 1970-01-01T01:00+01:00[Europe/Paris]
Again, for another time zone.
ZonedDateTime zdtEpochMontreal = Instant.EPOCH.atZone( ZoneId.of( "America/Montreal" ) ) ;
zdtEpochMontreal.toString(): 1969-12-31T19:00-05:00[America/Montreal]
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
With a JDBC driver complying with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings or java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.