Running the following code:
String s = "1914-07-20T00:00:00+0200";
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
System.out.println(df.parse( s ));
I get this result:
Sun Jul 19 23:34:52 EET 1914
(notice the date and hour)
It's probably one of those time adjustments that took place to get the sun to be overhead at noon. These took place around that time as the world got smaller and local time zones were being replaced by more universal ones. 25 minutes could well be such an adjustment. You would have to look at the record of time zone adjustments for eastern Europe from then to now.
An alternate way to check this is to put this in a loop and see it it works right in 1924 and 1934 and so forth until now. At some point, if its such an adjustment, it might start working and you could narrow it down to a particular time at which all times after work as expected and all times before don't. Though, to be sure, there could be a sequence of adjustments. 10 minutes here and 7 minutes there that add up the 25 minutes.
Note
This page (http://www.prokerala.com/travel/timezones/EET?mode=history) shows the GMT offset as 1.64444 in 1901 and 2 in 1920. That's 39:52 minutes and seconds.
This page (http://home.tiscali.nl/~t876506/TZworld.html) is about the global tz database and shows a LMT (local mean time) of 1:34:52 for Europe/Athens which is theoretically supposed to be +2:00. I'm not quite sure what that has to do with it but it seems a strange coincidence to be exactly what OP is seeing. (I also found that joda-time uses the LMT offset for any dates prior to the first entry in the "official" timezone data file.
Related
I'm trying to modify the existing java code to output the data in milliseconds instead of seconds.
existing code which return current time in GMT in seconds:
currentTime = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC);
output currentTime = 1566311076
using epoch converter it says
GMT: Tuesday, August 20, 2019 2:24:36 PM
Your time zone: Tuesday, August 20, 2019 7:24:36 AM GMT-07:00 DST
My attempt to modify the java code to return current time in GMT in millisec is able to get current system time in millisec, however how do I offset the result to GMT time.
currentTime = ZonedDateTime.now().toInstant().toEpochMilli();
output currentTime = 1566336256566
Assuming that this timestamp is in milliseconds
GMT: Tuesday, August 20, 2019 9:24:16.566 PM
Your time zone: Tuesday, August 20, 2019 2:24:16.566 PM GMT-07:00 DST
do you know , will greatly appreaciate that. Thanks!
Convert to Instant first:
currentTime = LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli()
Demo
System.out.println(LocalDateTime.now().toEpochSecond(ZoneOffset.UTC));
System.out.println(LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli());
Output
1566323773
1566323773363
Why do it in a more complicated way when a simple one exists?
long currentTime;
currentTime = System.currentTimeMillis();
System.out.println(currentTime);
Example output from just now:
1566369127348
I am a strong proponent of using the modern java.time classes including ZonedDateTime (maybe not so much LocalDateTime). However in this case a simple method from when Java was born gives us what we want. I see no issues with using it. If you do want to use java.time, use Instant:
currentTime = Instant.now().toEpochMilli();
System.out.println(currentTime);
1566369127348
What went wrong in your code?
Curiously your old code was incorrect. Your new attempt gives the correct number of milliseconds since the epoch. Your old code was:
currentTime = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC);
This takes the current wall-clock time in your time zone, or more precisely, in the default time zone of your JVM. It then incorrectly assumes that the time is in UTC and converts it to seconds since the epoch based on this assumption (of course, if the JVM’s time zone had been UTC, you would have happened to get the correct result).
I recommend you always pass a time zone (if not a clock) to a now method to make your expectations of the time zone used explicit. The no-arg now uses the JVM’s default time zone, which is unreliable because the setting can be changed unexpectedly, and may cause confusion. If the time zone had been stated in the above code line, we would all have been able to see at a glance whether it agreed with the UTC assumed afterward or not. The exception is Instant.now(): it doesn’t need a time zone since it gives the same result in all time zones.
Output from your old code on my computer in Europe/Copenhagen time zone was:
1566376327
You can see that it doesn’t agree with the millisecond values we got before (it’s two hours ahead in this case; in your case it was 7 hours behind).
Your question seems to have been posted some time around 10 PM (22:00) GMT (3 PM at offset -07:00), so none of your results fit well with that time. Either some hours went by from running your code to posting your question; or your computer clock is set incorrectly.
As part of some logic, it is necessary in my program to turn a long Java timestamp (including year, month, etc.) to a 'short' Java time. This should correspond to exactly the same hours, minutes and seconds of the original time, but within 1 day of Jan 1 1970 (i.e. a value between 0 (00:00:00) and 86400000 (23:59:59)). An example is the conversion in the question.
In order the perform this, I thought the below code would work:
public int convertToTime(long fullTimeStamp) {
Calendar c = Calendar.getInstance();
c.setTimeInMillis(date);
c.set(Calendar.DATE, 1);
c.set(Calendar.MONTH, 0);
c.set(Calendar.YEAR, 1970);
return (int) c.getTimeInMillis();
}
The issue I am having is to do with timezones. In the UK we are currently in BST. After setting all the values with the function, the time remains the same numbers (e.g. 8.00am) but changes the timezone to GMT! 8.00am GMT is of course not the same as 8.00am BST, and is instead equal to 9.00am BST.
Adding some console output to the function demonstrates this issue:
public int convertToTime(long fullTimeStamp) {
System.out.println(new Date(fullTimeStamp)); // correct
Calendar c = Calendar.getInstance();
c.setTimeInMillis(fullTimeStamp);
System.out.println(c.getTime()); // correct
c.set(Calendar.DATE, 1);
c.set(Calendar.MONTH, 0);
c.set(Calendar.YEAR, 1970);
System.out.println(c.getTime()); // incorrect!
return (int) c.getTimeInMillis();
}
Program output:
Wed Jun 19 12:15:00 BST 2013 // ok
Wed Jun 19 12:15:00 BST 2013 // this makes sense
Thu Jan 01 12:15:00 GMT 1970 // Calendar, stahp!
The desired behaviour is for the last part to read:
Thu Jan 01 11:15:00 GMT 1970
or
Thu Jan 01 12:15:00 BST 1970
Is this expected behaviour of the calendar? My understanding was that it keeps all the 'digits' the same that aren't modified, so if the value of HOUR_OF_DAY is 8, it should stay at 8, even if the timezone is modified.
I have tried setting the timezone on the calendar (before any values are set) to BST and GMT and exactly the same behaviour occurs. I also cannot manually add or remove milliseconds to delete all years after 1970 as I will have to handle leap years.
Aside from 'use Joda time (or some other time package)' does anyone have any other suggestions to perform this operation? I kind of need to get a quick fix in before experimenting with other packages if possible.
Thanks!
I think you're running foul of a little-known fact about the UK time zone: at the Unix epoch, we were actually in UTC+1. Java is getting the time of day right (within the UK time zone), but the name wrong - it shouldn't be specifying GMT, but BST. This isn't BST as in British Summer Time; it's BST as in British Standard Time. Yes, it's that mad.
From the relevant wikipedia article:
An inquiry during the winter of 1959–60, in which 180 national organisations were consulted, revealed a slight preference for a change to all-year GMT+1, but the length of summer time was extended as a trial rather than the domestic use of Greenwich Mean Time abolished.[8] A further inquiry during 1966–67 led the government of Harold Wilson to introduce the British Standard Time experiment, with Britain remaining on GMT+1 throughout the year. This took place between 27 October 1968 and 31 October 1971, when there was a reversion to the previous arrangement.
It's worth bearing in mind that your original problem statement is somewhat ambiguous: you're taking in a long, which is just the millis since the Unix epoch - but then you're trying to interpret it in terms of the hour of day, which immediately begs the question of which time zone you need to interpret it in. Have you made that decision? If so, you should document it very carefully, and make sure your code complies with it.
Ultimately, my recommendations are:
If you can possibly use Joda Time, do so. It will save you hours and hours of heartache.
If you're trying to calendar calculations like this, consider changing the time zone of the calendar to UTC before doing anything else; it will save you some heartache
Avoid using Date.toString() where possible - you could use a DateFormatter with the time zone set to UTC, and then you would see the expected results
As user2340612's answer states, to get just the "millisecond of UTC day" you can use simple arithmetic - but not quite with the values given. I would use:
long timeOfDay = millisecondsSinceUnixEpoch % TimeUnit.DAYS.toMillis(1);
... but this only works if you're interested in the UTC time of day for the given instant. (It will also give a negative result for negative input, but you may not care about that.)
If you need a timestamp between 0 and 86399999 (which is 23:59:59.999) you can get the current timestamp and calculate the remainder of the division between it and 86400000:
desired_time = cur_time % 86400000
But you'll miss the summer time, if present.
The java function System.currentTimeMillis() apparently returns the number of seconds since 1st January 1970. However, according to wikipedia.org/wiki/Leap_second, since 1972 there have been 25 leap seconds. This means the actual number of seconds since 1st January 1970 has been 25 more than a naive calculation would suggest. Does System.currentTimeMillis() do the naive calculation and ignore the leap seconds?
Officially, it's up to the OS and implementation - at least for Date. From the docs of java.util.Date:
Although the Date class is intended to reflect coordinated universal time (UTC), it may not do so exactly, depending on the host environment of the Java Virtual Machine. Nearly all modern operating systems assume that 1 day = 24 × 60 × 60 = 86400 seconds in all cases. In UTC, however, about once every year or two there is an extra second, called a "leap second." The leap second is always added as the last second of the day, and always on December 31 or June 30. For example, the last minute of the year 1995 was 61 seconds long, thanks to an added leap second. Most computer clocks are not accurate enough to be able to reflect the leap-second distinction.
I suspect you'll find that although your computer clock is roughly aligned to UTC, that's done via NTP or the like correcting the clock periodically, rather than the OS really implementing leap seconds.
I believe the JRE libraries typically do assume the 86400-second day. It makes life so much simpler, and if you're going to correct for an inaccurate system clock anyway, you might as well correct for leap seconds that way too.
You really want to work out what you're interested in. If you need a way of representing dates and times which use leap seconds, the standard Java libraries may not work well for you. Even JSR-310 no longer supports leap seconds as far as I can tell (which is a very sensible decision for most developers).
POSIX requires that the system clock not admit the existence of leap seconds. MS Windows cannot guarantee the quality (nor existence) of the system clock hardware, and it has eschewed guarantee of 1-second accuracy. Java cannot easily do anything that the underlying system refuses to do. The operating systems are hamstrung by the history of the international regulations that result in one IEEE standard (PTP) that requires leap seconds and another (POSIX) that denies them.
One easy way to check if leap seconds are accounted for or not is to compute the number of seconds elapsed since the Epoch for 00:00 on any given day in the current year.
If that number of seconds is congruent to 00 modulo 60, then the leap seconds are not accounted for as in 2013 you should have a modulus of 25 (to account for the past 25 leap seconds).
I did a small experiment on javarepl:
java> new Date(1000L * 86400 * (365 * 4 + 1) * 12)
java.util.Date res0 = Mon Jan 01 00:00:00 UTC 2018
As you can see, a simple "naive" arithmetics that just regards leap year, but not leap seconds, is used. No extra seconds are added or subtracted.
Update:
Same for the new Instant class:
java> Instant.ofEpochMilli(1000L * 86400 * (365 * 4 + 1) * 12)
java.time.Instant res0 = 2018-01-01T00:00:00Z
Looking at the Javadoc for currentTimeMillis(), it referes to the documentation of the Date class, which has this to say:
Although the Date class is intended to reflect coordinated universal time (UTC), it may not do so exactly, depending on the host environment of the Java Virtual Machine. Nearly all modern operating systems assume that 1 day = 24 × 60 × 60 = 86400 seconds in all cases. In UTC, however, about once every year or two there is an extra second, called a "leap second." The leap second is always added as the last second of the day, and always on December 31 or June 30. For example, the last minute of the year 1995 was 61 seconds long, thanks to an added leap second. Most computer clocks are not accurate enough to be able to reflect the leap-second distinction.
So to answer your question: Yes, leap seconds are accounted for.
Assuming Brasilia GMT -0300: DST on 21/10/2012 at 00:00:00, when the clock should be advanced by one hour
Java
new Date(2012 - 1900, 9, 21, 0, 0, 0)
Sun Oct 21 01:00:00 BRST 2012
Chrome/FireFox (console)
new Date(2012, 9, 21, 0, 0 ,0)
Sat Oct 20 2012 23:00:00 GMT-0300 (Hora oficial do Brasil)
The result in Java is what I was expecting, but the result in JS I can not understand. I found this post where bjornd says
This is an absolutely correct behavior
but didn't explain why this behavior is OK.
My question is:
Why JS is returning a date one hour in the past?
P.S. I know Date is marked for "deprecation", but I'm using GWT; Date is my only option.
Basically, that answer was incorrect as far as I can see. I'm not entirely happy with the Java version, even.
Fundamentally, you're trying to construct a local date/time which never happened. Translating from local time to UTC is always tricky, as there are three possibilities:
Unambiguous mapping, which in most time zones is the case for all but two hours per year
Ambiguous mapping, during a backward transition, where the same local time period occurs twice (e.g. local time goes 12:59am, 1am, ... 1:59am, 1am, 1:59am, 2am)
"Gap" mapping, where a local time period simply doesn't exist (e.g. local time goes 12:59am, 2am, 2:01am)
Brazil moves its clocks forward at midnight, so local time actually goes:
October 20th 11:58pm
October 20th 11:59pm
October 21st 01:00am
October 21st 01:01am
The local time you've asked for simply never happened. It looks like Java is just assuming you want to roll it forward... whereas JavaScript is getting confused :( The JavaScript result would be more understandable (but still incorrect) if you were asking for midnight at the start of February 16th 2013, for example - where the clocks would have gone back to 11pm on the 15th. 12am on the 16th is unambiguous, as it can only happen after the "second" 11pm-11:59pm on the 15th.
A good date/time API (in my very biased view) would force you to say how you want to happen ambiguity and gaps when you do the conversion.
First of all, I know I can use Calendar, but I want to understand this problem and learn to solve it.
I have a Date with the current date. I want to set hours, minutes and seconds to 0. I do it with this code:
current_date.setHours(0);
current_date.setMinutes(0);
current_date.setSeconds(0);
Something is going wrong because if I do that, the day gets decreased by 1, for example, if today is 31, the day gets set to 30.
why? How can it be solved with Date (without using Calendar, I want to learn how to solve this problem by the hard way). Thanks
Just guessing...
I guess it has to do with time-zone.
When you set HMS to 0 you are not setting them according to your time zone, but according to UTC (not 100% sure, but...). So the resulting date is not:
0:0:0 YOUR LOCAL
but
0:0:0 GMT
and that's a day before if you are on America.
Try to set minutes to -yourDate.getTimezoneOffset() (try with positive value if it doesn't work).
Look at the implementation of these methods. They use a gregorian calendar. The error might come from that interaction.
Note: The set methods are all deprecated since JDK 1.1 see