Time difference respecting day light savings - java

I have two longs representing time since the epoch. They both have the same timezone. I want to find the difference in seconds between these two times, respecting day light savings.
(def a (java.util.Date. 1259568796000)) ;; Before Day Light Savings
(def b (java.util.Date. 1255147200000)) ;; After Day Light Savings
Where 'a' is 2009-11-30T08:13:16.000-00:00
and
Where 'b' is 2009-10-10T04:00:00.000-00:00
Using JodaTime, I can make an Interval out of these two times, turn them into a Duration, and get the StandardSeconds.
(.getStandardSeconds (.toDuration (Interval. a b)))
This doesn't work though, because the docs for Period indicate that Duration will mess up Day Light Savings:
When this time period is added to an instant, the effect is of adding
each field in turn. As a result, this takes into account daylight
savings time. Adding a time period of 1 day to the day before daylight
savings starts will only add 23 hours rather than 24 to ensure that
the time remains the same. If this is not the behaviour you want, then
see Duration.
How can I accomplish this task?

The long in Java represents a certain point in time (milliseconds since midnight on 1.1.1970, ignoring leap seconds). They don't carry a time zone and do not switch with daylight savings time, it is always expressed in UTC. To find the difference in seconds between two such timepoints you can use
(secondTime - firstTime) / 1000
The two times you have given are expressed in GMT, i.e.
1259568796000 = 2009-11-30T08:13:16.000-00:00 GMT
1255147200000 = 2009-10-10T04:00:00.000-00:00 GMT
And GMT does not switch to daylight savings time either. Maybe you were confused by that.

The java.util.Calendar class has support for daylight savings. Perhaps run your dates through that first? It should do the normalization for you. Check out this other post.

Related

java.time.Instant.atZone(...) far in the past return crazy values

I detect the following output when converting an Instant that is far in the past to a ZonedDateTime.
Code as Unit-Test:
#Test
public void testParseDate() {
Instant instant = Instant.parse("0000-12-30T07:00:00Z");
System.out.println(instant);
System.out.println(instant.atZone(ZoneId.of("Europe/Berlin")));
instant = Instant.parse("1800-12-30T07:00:00Z");
System.out.println("---------------------------------");
System.out.println(instant);
System.out.println(instant.atZone(ZoneId.of("Europe/Berlin")));
instant = Instant.parse("1900-12-30T07:00:00Z");
System.out.println("---------------------------------");
System.out.println(instant);
System.out.println(instant.atZone(ZoneId.of("Europe/Berlin")));
}
Output:
0000-12-30T07:00:00Z
0000-12-30T07:53:28+00:53:28[Europe/Berlin]
---------------------------------
1800-12-30T07:00:00Z
1800-12-30T07:53:28+00:53:28[Europe/Berlin]
---------------------------------
1900-12-30T07:00:00Z
1900-12-30T08:00+01:00[Europe/Berlin]
In the first two outputs the time is 07:53:28+00:53:28 and the last output is 08:00+01:00[Europe/Berlin]. Maybe the root cause is that the time zone stuff doesn't yet exists in the years of the first two examples, but the offset of +00:53:28 is really strange.
Any idea where this offset "+00:53:28" comes from?
Because history.
On April 1st, 1893, the time zone was adjusted from Local Mean Time (LMT), a local time zone (which was common at that time), to Central European Time (CET), adjusting the clock by 6 minutes and 32 seconds.
Timezones are regularly changed due to political decisions, but those strange amounts like 6 minutes and 32 seconds are often the result of moving from a local mean time to a standardized time.
Many known historical changes are found at timeanddate.com, and Berlin specifically at https://www.timeanddate.com/time/zone/germany/berlin.
Timezones, Daylight Saving, and all those annoying and fancy features, did not exist at the beginning of the 20th century.
There were many "variations" of the time, like the infamous Dutch Time which was about 19 minutes ahead of UTC, mostly based on the clock of a tower which was simply that amount of time ahead.
I don't know exactly where the time difference comes from in the case of Germany and Berlin, but it's a known offset (likely based on similar reasons as the Dutch Time).
You can see how it has evolved over time.

Joda: get local milliseconds of specific timezone

I never would believe that this could amount to being such a hassle. I am trying to make a clock that always displays the local time in specific timezones.
My laptop is currently set in GMT0 timezone (UK).
I want to get the milliseconds of the timezone "Europe/Stockholm".
So let's say it's 17:00 here in the UK I would like to get the milliseconds corresponding to 18:00 which would be the Swedish time.
The time in milliseconds as used by Date is independent of the time zone. Only when you print (or parse) a time, you use a DateFormat that is localized, so it ensures you get the time in the specific timezone.
When time is represented as milliseconds (or seconds or nanoseconds, etc), that is almost always milliseconds since some epoch. In the case of unix and java, this is midnight Jan 1, 1970 UTC.
Time zones are generally arranged as a round number of hours relative to UTC. In certain time zones it's not a round hour but 30 minutes, 15 minutes or 45 minutes from a round hour.
Nevertheless, for any time unit below a minute, all those time zones match UTC exactly.
Therefore, whatever the current second or millisecond is in Sweden, it is the same as it is, for example, in Nepal, whose time zone is 5:45 minutes from UTC.
When you work with an object that allows you to retrieve the separate fields of the given time, the milliseconds field will usually reflect just the number of milliseconds since the beginning of the current second, not the number of milliseconds since midnight. Therefore it will never be more than 999, and it will be the same the world over.
After reading the answers here and discovering another route, this is what finally worked for me.
DateTime curDateTime = new DateTime();
int offset = DateTimeZone.forID("Europe/Stockholm").getOffset(curDateTime.getMillis());
long milli = (curDateTime.getMillis()+offset);

Calculating local time offset from GMT time

I have a requirement where I only have GMT time without any offset, example 15:00:00, my requirement is to find out what timezone this GMT time belongs to, I have tried to solve it by using my local time and converting it to GMT time and doing some comparison but I don't think that it might be the right way to do it.
Assuming that the time is definitely offset from GMT, you should be able to produce a GMT timestamp using the following, and then compare the two. Your resulting answer, converted back to hours, should be the offset, which you can then lookup.
new Date().getTime();
Note that this doesn't take into account daylight savings/summer time etc, and assumes that the time given is right now, and can therefore be compared to the current GMT time. Specifically, remember that a timezone can fluctuate by a couple of hours if, like the UK and Australia, their summer/winter periods are reversed, so a +11 hour time zone offset may actually be +10 or +12 at any given point in time. And some countries don't use DST at all, even in the same time zone.
Note also that the entire point of time zone offsets and use of a centralised time (eg UTC) is to avoid the above confusion. By definition, you're doing things the long way round and introducing levels of uncertainty.
You may therefore have one country in the northern hemisphere varying +/- 1 hour, one in the southern varying -/+ 1 hour, and one near the equator using the same time constantly... and you'd have no idea which ones are meant to be in that time zone. You can find the offset, but that's about it.

Does this account for daylight savings?

// someTime is epoch in millis (UTC)
final long timeNow = new Date().getTime();
final long midnight = timeNow - timeNow % (3600 * 24 * 1000L);
final long yesterdayMidnight = midnight - (3600 * 24 * 1000L);
// check if same day.
if (someTime >= midnight)
// do something
// check if yesterday
if (someTime >= yesterdayMidnight)
Edited: My purpose is to check whether someTime is in the same day or in the previous day without doing too much heavyweight stuff.
Does this account for day light savings and why? If not, what's the simplest logic?
Your current code doesn't do anything with the local time zone - everything is in UTC, effectively (certainly in terms of your code, which is dealing in "milliseconds since the Unix epoch").
If you want to make your code time-zone-sensitive, you should use (in order of preference):
Java 8's java.time (look at ZonedDateTime and Clock for example)
Joda Time
java.util.Calendar with java.util.TimeZone
Use higher-level abstractions where possible - your code should do as little low-level manipulation of time as possible.
EDIT: Now that we know the purpose, here's an example implementation in Joda Time:
public void calculate(Instant now, Instant then, DateTimeZone zone) {
LocalDate today = new LocalDate(now, zone);
LocalDate otherDay = new LocalDate(then, zone);
if (otherDay.equals(today)) {
// Today day
} else if (otherDay.equals(today.minusDays(1)) {
// Yesterday
} else {
// Neither today nor yesterday
}
}
Note how there's nothing low level here - we're just working out which date each value (now and then) falls in within the given time zone, and then comparing those.
Your check will fail in some cases having in mind daylight savings. Let's assume it is now 5 o' clock on the day when daylight saving happens and at 3 o'clock we've switched the clock forward. Therefor only 4 hours have passed since midnight but it is in fact 5. So midnight in your code will be a time 5 hours ago. This means that if someTime is between 5 hours ago and 4 hours ago(e.g. 4 hours and a half ago) when it's in fact been yesterday your algorithm will report it has been today.
That does not seem to be correct from daylight savings point. First, what's the timezone of someTime date? What about the days/nights(in fact) when the daylight savings take place (one hour +/-)?
If you use Joda lib there is a convenient method DateTime.isBefore() that will return whether one date is before another.

Determining if a time stamp is an exact hour

I need to determine if a time stamp is an exact hour (i.e. it represents a time with no minutes, seconds or milliseconds components) - using primitives only. The code is called several hundred times per second and I don't want the overhead of a Calendar or other object.
I've tried this but rounding errors cause the comparison to fail.
float hours = (time / 3600000f);
boolean isExactHour = hours == (int)hours;
For example, if time = 1373763600470, hours = 381601.03125. That time stamp represents 01:00:00:000 GMT today and hours should be 381601.
Any ideas for a quick and simple way to do this? Thanks!
[EDIT]
It seems that this is more complex than at first sight (when is it not? :)
For clarity, I don't care about time zones, nor leap seconds. The time stamp is generated by a method which returns the previous midnight - i.e. 13 July 2013 00:00:00:000 for today. I am then calculating, for any time stamp in an array of longs which is always this initial time stamp plus/minus an exact multiple of 5 minutes. My aim to to determine if a given stamp is "top of the hour". I might have edge cases where the multiple of 5 minutes overlaps a year end but I can live with those.
(time % 36000000) == 0
Surely this is obvious?
EDIT
To get accuracy w.r.t. leap seconds, assuming a lookup table of leap seconds indexed by year since (say) 1970, something like:
((time-leapSeconds[(int)(time/(1000*60*60*24*365.2425))-1970]*1000) % 3600000) == 0
Programmers needing this level of accuracy should also see all of Einar's comments below.

Categories

Resources