Probably, this question is asked many times but I might not find the correct keywords to find them.
There was a time change at 30.10. The time was set back to 2 o'clock at 03:00 o'clock (Europe/Berlin). That means, at that day, there were two 02:00 o'clock (before and after time change)
Currently, I have two date (java.util.Date) objects. One of them was created at the first 02:00 o'clock (before the time was set back) and the second one was created at the second 02:00 o'clock.
Is there any way to differentiate these objects based on whether it was created at the first or second 02:00 o'clock?
Count from epoch
Your java.util.Date objects actually are in UTC but their toString method confusingly applies a time zone when generating the string output.
You can differentiate two Date objects by interrogating for their count from epoch. Internally the date-time is tracked as a number of milliseconds since first moment of 1970 in UTC. Call the badly-named method java.util.Date::getTime to get a long.
UTC
Record moments in UTC. Every programmer should learn to think in UTC, work in UTC, do logging in UTC, and keep a second clock on their desk and screen set to UTC.
UTC is the One True Time. All others are mere variations, every time zone being a deviation from UTC.
Let me repeat the acronym one more time to be clear: UTC
Instant
The Instant class is your new best friend in this arena, your go-to class for date-time work. It represents a moment on the timeline in UTC with a resolution of nanoseconds.
Instant instant = Instant.now() ;
You need not worry about Daylight Saving Time (DST) cut-overs, politicians redefining DST ( often with little notice), nor other anomalies particular to any one time zone. Just use UTC.
To generate a String representing this moment, call toString for a string in standard ISO 8601 format. This string is always in UTC, so you don't have the problem of Date::toString applying a time zone while generating the string. The standard format has a Z on the end, short for Zulu, and means UTC.
instant.toString(): 2016-01-23T12:34:56.123456789Z
Converting Date
Convert your java.util.Date objects to Instant. New conversion methods have been added to the old classes.
Instant instant = myUtilDate.toInstant();
Zoned
I do not care about Berlin time. You, as a programmer, do not care about Berlin time. Your network and server admins do not care about Berlin time. We care about UTC.
The only people who care about Berlin time are end-users. For them, you can assign a time zone for presentation of data.
ZoneId z = ZoneId.of( "Europe/Berlin" );
ZonedDateTime zdt = instant.atZone( z );
Call toString to generate a String in standard ISO 8601 format but wisely extended by appending the name of the time zone in square brackets.
2016-07-07T08:00:15.768+02:00[Europe/Berlin]
Use DateTimeFormatter class to generate Strings representing the date-time value in other formats.
DST in effect?
You can interrogate to determine if Daylight Saving Time (DST) is in effect for any particular ZonedDateTime. See this Question.
ZoneRules rules = zdt.getZone().getRules();
Boolean dstInEffect = rules.isDaylightSavings( zdt.toInstant() );
Related
I am trying to understand LocalDate and LocalDateTime. Since they do not carry zone info, how does it work for now() on two different time zone.
Example:
Server 1(EST time zone):
LocalDateTime.now() -> 2020-04-06T23:00:00.040
LocalDate.now(). -> 2020-04-06
Server 2(UTC time zone):
LocalDateTime.now() -> What would be the value?
LocalDate.now(). -> What would be the value? (Note in EST, time it executed was 11 PM)
Also,
If I convert below date string to LocalDateTime and then toLocalDate, what would be the outcome?
2020-04-06T23:00:00.000
Offsets vary over time
On April 6, 2020, most time zones on the east coast of North America such as America/Montreal and America/New_York use an offset of four hours behind UTC.
So, in those zones 11 PM on 2020-04-06 is simultaneously 3 AM on the 7th in UTC. Add four hours to 2020-04-06T23:00 to get 2020-04-07T03:00. Adding four hours brings us from the wall-clock time used in America/Port-au-Prince and America/Nassau to UTC.
The offset used by the time zones mentioned above are four hours behind UTC only half the year. The politicians in those locations have decided to observe Daylight Saving Time (DST) for about half the year. So half the year they jump their clocks ahead an hour for an offset-from-UTC of -04:00, and later in the year they fall back an hour for an offset-from-UTC of -05:00. For example, earlier in the year 11 PM in America/New_York would be 04:00 in UTC rather than the 03:00 time seen in April.
Standard time, in January, is five hours behind UTC. So, 11 PM plus five hours is 4 AM next day.
ZoneId z = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdt = ZonedDateTime.of( 2020 , 1 , 6 , 23 , 0 , 0 , 0 , zNewYork ) ;
Instant instant = zdt.toInstant() ; // 2020-01-07T04:00Z
Daylight Saving Time, in April, is four hours behind UTC. So, 11 PM plus four hours is 3 AM next day.
ZoneId z = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdt = ZonedDateTime.of( 2020 , 4 , 6 , 23 , 0 , 0 , 0 , zNewYork ) ;
Instant instant = zdt.toInstant() ; // 2020-04-07T03:00Z
By the way, DST is only one of many reasons politicians have for changing the offset used by the time zone(s) of their jurisdiction. Politicians around the world have shown a penchant for changing their offsets surprisingly often. Your programming should always expect a time zone to change its offset. Just because your particular zone of concern does not currently observe DST does not mean the offset will never change.
As for parsing 2020-04-06T23:00:00.000 as a LocalDateTime, you will get 2020-04-06T23:00:00.000. Ignoring time zones is the entire point of LocalDateTime. So no adjustments are made.
You may be thinking of LocalDateTime as representing a particular locality. But, no, it represents any locality or all localities. But never any one particular locality. For a particular locality, use ZonedDateTime.
Pseudo time zones
Another point: EST is not a time zone. Such 2-4 letter letter codes are not real time zones, are not standardized, and are not even unique. For example, by EST, did you mean Australian Eastern Standard Time or North American Eastern Standard Time? Is CST Central Standard Time or China Standard Time? Avoid these pseudo-zones in your date-time-handling.
And you happened to use the wrong pseudo-code. On April 6 2020, most of those east coast time zones are observing Daylight Saving Time (DST). So they would be considered to be in “EDT” rather than “EST”. Avoid the problem by specifying the real time zone name.
Real time zones are named using Continent/Region format. See Wikipedia for a list of real time zones.
Never call LocalDateTime.now
I cannot imagine a case where calling LocalDateTime.now would be the right thing to do. Determining the current moment requires a time zone (or offset). And LocalDateTime by definition has no time zone or offset. When a programmer writes LocalDateTime.now, you can bet they do not fully understand the necessary concepts.
When you call LocalDateTime.now, the JVM’s current default time zone is implicitly used to capture the current time as seen by the people in the region of that zone. And then the fact of that time zone is deleted.
This:
LocalDateTime.now()
…is the same as this:
LocalDateDate.now( ZoneId.systemDefault() )
…which is the same as getting the current moment as seen in a particular time zone, followed by removing the time zone information:
ZonedDateTime.now( ZoneId.systemDefault() ).toLocalDateTime()
For more code examples demonstrating LocalDateTime.now, see the correct Answer by Ole V.V.
Where to use LocalDateTime
If LocalDateTime is not appropriate for getting the current moment, and is not appropriate for tracking any moment, what is the appropriate use for this class? Three things: representing any locality, representing all localities, and booking future appointments.
Any locality would be something like stating when Christmas starts. This year Christmas starts at 2020-12-25T00:00 wherever you are in the world. Of course this means Christmas starts first in Kiribati after midnight, later in Japan after midnight, even later in Tunisia after midnight, and still later in Chicago after midnight.
All localities would be something like stating our company policy that lunch breaks at all our factories in Delhi, Düsseldorf, and Detroit are scheduled for 12:30. So on April 6 2020, the break will be at 2020-04-06T12:30:00. This break will occur first in Delhi, several hours later in Düsseldorf, and even more hours later in Detroit.
Booking future appointments where you intend to keep the same time-of-day regardless of changes to the time zone’s offset must recorded without the offset. If your next dental appointments is in six months at 3 PM, we want to record the 3 PM without regard for the offset. If the offset were to be changed by politicians, we still want the appointment to start when the clock strikes three on that date in that zone.
Set the appointment.
LocalDateTime appointment = LocalDateTime.of( 2021 , 1 , 23 , 15 , 0 , 0 , 0 ) ;
Determine a moment for producing a calendar. Every time you do this, you may get a different result if the politicians have changed the rules of this time zone.
ZoneId z = ZoneId.of ( "America/Panama" ) ;
ZonedDateTime dueToArrive = appointment.atZone( z ) ;
LocalDate
As for LocalDate, we saw in the examples above that the date depends on time zone. For any given moment, the date varies around the globe by time zone. It may be “tomorrow” in Tokyo Japan while still “yesterday” in Montréal Québec Canada.
So, you must specify a time zone when asking for the current date.
LocalDate ld = LocalDate.now( ZoneId.of( "Asia/Kolkata" ) ) ;
If you omit the time zone, the JVM’s current default time zone is implicitly applied. So LocalDate.now() becomes LocalDate.now( ZoneId.systemDefault() ). I recommend specifying your desired/expected zone explicitly, rather than rely on implicit default.
Server time zone
You said:
server which runs in EST vs UTC
FYI, servers should generally be set to UTC. Most of your thinking, programming, logging, and so on should be done in UTC. Learn to think of UTC as The One True Time, with all other zones but mere variations.
As a programmer, you should never rely on the default time zone. That is far outside your control. That default can be changed so easily by the user or sysadmin. Furthermore, any code in any thread of any app within the JVM can instantly change the JVM’s current default time with a call to TimeZone.setDefault. So even during execution of your app, the default can be changed at any moment.
To prevent confusion pass explicit time zone to now() and see for yourself:
ZoneId easternTime = ZoneId.of("America/Montreal");
System.out.println(LocalDateTime.now(easternTime));
System.out.println(LocalDateTime.now(ZoneOffset.UTC));
System.out.println(LocalDate.now(easternTime));
System.out.println(LocalDate.now(ZoneOffset.UTC));
Output when I ran just now:
2020-04-06T09:56:17.381558
2020-04-06T13:56:17.385215
2020-04-06
2020-04-06
While you are correct that LocalDateTime and LocalDate don’t contain any time zone information, their now methods do use time zones. Either the one passed to them, or if you use the no-arg variant, the default time zone of the JVM.
You also asked:
Also, If I convert below date string to LocalDateTime and then
toLocalDate, what would be the outcome?
2020-04-06T23:00:00.000
Why not try out that too?
LocalDateTime ldt = LocalDateTime.parse("2020-04-06T23:00:00.000");
System.out.println(ldt);
LocalDate ld = ldt.toLocalDate();
System.out.println(ld);
2020-04-06T23:00
2020-04-06
Converting from LocalDateTime to LocalDate involves no time zone (or UTC offset) whatsoever. The time part is simply discarded and the date part kept unchanged.
Is it possible to get a TimeZone ID from a certain TimeStamp ? If it is please explain by a simple code.
private String getDate(long timeStamp) {DateFormat objFormatter = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
TimeZone timeZone = TimeZone.getTimeZone("GMT+4:30");
//Instead of the Above code I want to get the TimeZone ID from my timeStamp objFormatter.setTimeZone(timeZone);
Calendar objCalendar =
Calendar.getInstance(timeZone);
objCalendar.setTimeInMillis(timeStamp * 1000);
String result = objFormatter.format(objCalendar.getTime());
objCalendar.clear();
return result;
}
tl;dr
Impossible to derive offset/zone from a count-from-epoch-in-UTC. But you can adjust into a zone.
Instant.ofEpochSecond( yourCount )
.atZone( ZoneId.of( "Pacific/Auckland" ) )
Avoid count-from-epoch
Firstly, avoid using a count-from-epoch number to track date-time values. Do you mean a count of whole seconds, milliseconds, microseconds, nanoseconds, or something else? Do you mean the Unix/Java epoch of 1970-01-01T00:00:00Z or one of the couple dozen other epochs in use by many computer systems?
Apparently you have whole seconds, and I'll assume the Unix/Java epoch.
Impossible to get zone from count-from-epoch
You cannot “ get a TimeZone ID from a certain TimeStamp”, that is impossible. Your count-from-epoch was made while accounting for a certain time zone, usually UTC. If must know that intended zone used in creating that count-from-epoch, it cannot be deduced.
Perhaps your goal is actually adjusting this count-from-epoch into a date-time for a particular region’s time zone. Read on.
java.time
Avoid the troublesome old date-time classes such as Date & Calendar now supplanted by the java.time classes.
Convert your count-from-epoch into a point on the timeline in UTC.
Instant instant = Instant.ofEpochSecond( yourCount ) ;
Assign your desired time zone.
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/Kabul" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
See this code run live at IdeOne.com.
Notice the 4.5 hour difference, changing from 02:40 to 07:10, appropriate for time in Kabul. This is the same moment, the same point on the time zone, but viewed through the lens of a different region’s wall-clock time.
input: 1500000000
instant: 2017-07-14T02:40:00Z
zdt: 2017-07-14T07:10+04:30[Asia/Kabul]
I would like to answer this question based on the definition of each terminology.
What is timestamp?
Timestamp or Unix Timestamp is the number of seconds that have elapsed since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970,minus the number of leap seconds that have taken place since then. Wikipedia
Wath is Time Zone?
A time zone is a region of the earth where the same standard time is used. Each time zone is described by an identifier and usually has the format region/city (Asia/Tokyo) and an offset from Greenwich/UTC time. For example, the offset for Tokyo is +09:00. Time Zone Oracle Doc
Regarding to both definitions there is no way to get a region of the earth based on a number of seconds (time), it is imperative to know from what region of the earth the time comes from.
If we have timestamps that contain the timezone info, like 2017-07-03T17:30:00-04:00, and parse it into java.Date or joda.DateTime.
Does it contains timezone information ?
I am asking this because i want to compare two different date instance. So if it does not contain timezone information, the day difference will be wrong with different timezones
UPDATE:
I run a quick unit test to verify, first convert date instance to milliseconds and convert back to TimeUnit after subtract these two milliseconds. The hours are different for different timezone
Both java.util.Date and Joda-Time have been supplanted by the java.time classes.
Your input string 2017-07-03T17:30:00-04:00 is in standard ISO 8601 format and has an offset-from-UTC at the end. That -04:00 means the string represents a moment four hours behind UTC.
This offset is not a time zone. A time zone is a history of offsets for a particular region. For example, America/Barbados or America/New_York.
Parse your string as an java.time.OffsetDateTime object.
OffsetDateTime odt = OffsetDateTime.parse( "2017-07-03T17:30:00-04:00" );
odt.toString(): 2017-07-03T17:30:00-04:00
You may compare OffsetDateTime instances by calling the methods IsEqual, isBefore, and isAfter.
To see the same simultaneous moment in UTC, extract an Instant.
Instant instant = odt.toInstant() ;
instant.toString(): 2017-07-03T21:30:00Z
The Z on the end is short for Zulu and means UTC.
It is going to depend on what type of DateTime you use, as of Java 8 you have these options:
A LocalDate or LocalDateTime. It is going to discard time zone information, you will wind up with a value that is 'valid' only for the local timezone. This value is ambiguous without some context as to the specific timezone of the server process which generated the value.
A ZonedDate or ZonedDateTime. This one preserves the time zone. Comparison is still going to be ambiguous: you have issues like DST or calendaring changes to contend with (depending on the range of datetime which you need to be compatible with). For sorting/comparison purposes you would probably want to convert it to a reference timescale, which is why:
An Instant represents a particular moment in time, on the absolute timescale of UTC. Any Instant is directly comparable with any other Instant and any ambiguity in values is resolved by the definition of Instant. Input values will be converted to the matching counterparts in UTC, so the original timezone (if any) will be lost even if the absolute time value will be preserved correctly. Instant is therefore not a good choice if you rely on the timezone to make decisions about location or locale, for instance.
In the code below I have used calendar object to initialize time Zone to GMT and get the time accordingly but when I put back in date object, its automatically converting to my local time zone i.e. IST.
Calendar gmt = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
Date dt=gmt.getTime();
Could anyone suggest a way through which I can retain the GMT format in date object also.
its automatically converting to my local time zone i.e. IST
No it's not. A Date object doesn't have a time zone - it's just an instant in time.
You'll see the system-local time zone if you call toString() on a Date, because that's unfortunately what Date.toString() does... but the time zone is not part of the information stored in a Date.
If you want to see a textual representation of a Date in a particular time zone, use DateFormat and set the time zone that you want to use.
java.time
The other answers are correct. The toString method silently applies your JVM’s current default time zone. This is one of many poor design choices in the old date-time classes. Dump those old classes. Move on to the java.time framework built into Java 8 and later.
An Instant is a moment on the time line in UTC.
Instant now = Instant.now();
Apply a time zone (ZoneId) to an Instant to get a ZonedDateTime.
Why are we bothering to create a ZonedDateTime in UTC if the Instant is already in UTC? Because a ZonedDateTime gives you flexibility in formatting String representations of the date-time values. The java.time.format package does not work with Instant objects.
A subclass of ZoneId, ZoneOffset, has a constant for UTC.
ZonedDateTime zdtUtc = ZonedDateTime.ofInstant( ZoneOffset.UTC );
Adjust into any desired time zone.
ZoneId zoneId = ZoneId.of( "Asia/Kolkata" );
ZonedDateTime zdtKolkata = ZonedDateTime.ofInstant( instant , zoneId );
Use proper time zone names
Avoid using 3-4 letter codes for time zones. They are neither standardized nor unique. By IST did you mean India Standard Time or Irish Standard Time?
Use standard time zone names. Most are in the pattern of continent/region. For India, Asia/Kolkata. For Ireland, Europe/Dublin.
The Date class does not represent a timezone. It's toString method uses the default platform time zone to output a human readable timestamp, internally it's just a long.
I have a data source with joda time DateTime objects stored. I need to convert them into java ZonedDateTime objects, keeping the original timezone.
It is not sufficient to keep the offset since some DateTime objects represents daily repetitive tasks, and these tasks must occur at a specific time in a specific time zone for every date. They must thus follow the specified TimeZone transitions for example summer and winter time. I cannot tell the final usage of the DateTime objects, so I need to keep the Time Zone information on all objects to be safe.
How to convert from org.joda.time.DateTime to java.time.ZonedDateTime?
Will all
ord.joda.time.DateTimeZone.getId()
map to the id's available in
java.time.ZoneId
You should avoid providing each field separately if you are working with daylight saving transitions. Convert using epochMillis instead, as in the following example.
Instant instant = Instant.ofEpochMilli(dt.getMillis());
ZoneId zoneId = ZoneId.of(dt.getZone().getID(), ZoneId.SHORT_IDS);
ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, zoneId);
Otherwise you will lose one hour on the date of transition. For example, Germany transitioned from summer time (GMT+2) to winter time (GMT+1) on 29.10.2017 at 03:00 GMT+2, which becomes 02:00 GMT+1. On that day, you have 2 instances of 02:00 - an earlier one with GMT+2 and a later one with GMT+1.
Since you are working with ZoneIds and not with offsets, there's no way of knowing which one of the 2 instances you want. By default, the first one is assumed during conversion. Both 02:00 GMT+2 and 02:00 GMT+1 are going to be converted to 02:00 GMT+2 if you provide hourOfDay along with ZoneId.
Not all time-zone strings from Joda-Time will match java.time but the vast majority will as they are both based on the IANA tz data. Compare DateTimeZone.getAvailableIDs() to ZoneId.getAvailableZoneIds() to determine the mismatch. Additional identifiers can be mapped using ZoneId.of(String, Map).
To do the main conversion in the most efficient way, you have to pass in each field:
ZonedDateTime zdt = ZonedDateTime.ofLocal(
LocalDateTime.of(
dt.getYear(),
dt.getMonthOfYear(),
dt.getDayOfMonth(),
dt.getHourOfDay(),
dt.getMinuteOfHour(),
dt.getSecondOfMinute(),
dt.getMillisOfSecond() * 1_000_000),
ZoneId.of(dt.getZone().getID(), ZoneId.SHORT_IDS),
ZoneOffset.ofTotalSeconds(dt.getZone().getOffset(dt) / 1000));
Note the use of ZoneId.SHORT_IDS as the Map in this case.
For a simpler solution that handles most use cases, but at lower performance, use this:
ZonedDateTime zdt = dt.toGregorianCalendar().toZonedDateTime();