I have an object Shift
, with two fields: startDateTime
and endDateTime
as DateTime
from Joda-Time.
And my shift includes Daylight Saving UK change. It starts on 25/03/2017 13:00
and ends on 26/03/2017 02:00
(basically should end on 26/03/2017 01:00
, but this date does not exists, and endDate
is shifted +1 hour). According to this site:
When local standard time was about to reach Sunday, 26 March 2017, 01:00:00 clocks were turned forward 1 hour to Sunday, 26 March 2017, 02:00:00 local daylight time instead.
Now if I want to track the number of hours worked by a employee
new Duration(startDateTime, endDateTime).toStandardHours().getHours()
will give me 13 hours.
How can I detect if Daylight Saving starts or ends on my shift duration using Joda-Time?
You can use org.joda.time.DateTimeZone
class. It has information about DST changes for all timezones in the world, so you don't need to detect the DST change: if you correctly inform which timezone you're using, the API does the job for you.
As you're working with UK timezone, you can use directly the Europe/London
timezone - these names in the format Continent/City
comes from the IANA database, and it's used by Joda-Time, Java and many other APIs. You can get a list of all timezones by calling DateTimeZone.getAvailableIDs()
.
When you use a DateTimeZone
, it already contains all the DST shifts during history, so the API does all the math for you. You just need to create your DateTime
instances at this timezone:
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.Duration;
// London timezone - it contains all info about DST shifts
DateTimeZone london = DateTimeZone.forID("Europe/London");
// Start on 25/03/2017 13:00
DateTime start = new DateTime(2017, 3, 25, 13, 0, london);
// ends on 26/03/2017 02:00
DateTime end = new DateTime(2017, 3, 26, 2, 0, london);
// get the difference between start and end
Duration duration = new Duration(start, end);
System.out.println(duration.getStandardHours()); // 12
The output will be 12
(the API uses the information of the DateTime
's timezones to calculate the difference, including DST shifts).
You can also use:
duration.toStandardHours().getHours()
Or the class org.joda.time.Hours
:
Hours.hoursBetween(start, end).getHours()
All of them return 12
, and they're all equivalent.
Java new Date/Time API
Joda-Time it's being discontinued and replaced by the new APIs, so if you're considering a migration, you can start using the new Date/Time API, but if you have a big codebase using Joda or don't want to migrate it now, you can desconsider the rest of the answer.
Anyway, even in joda's website it says: "Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310).".*
If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs. I'm not sure if it's already available to all Android versions (but see the alternative below).
If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's a way to use it, with the ThreeTenABP (more on how to use it here).
The code below works for both.
The only difference is the package names (in Java 8 is java.time
and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp
), but the classes and methods names are the same.
The new API also uses IANA timezones names and contains the same historical information about the DST shifts (to get a list of all timezones: ZoneId.getAvailableZoneIds()
). The code is very similar, and there's also more than one way to get the difference:
import java.time.Duration;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
// London timezone
ZoneId london = ZoneId.of("Europe/London");
// Start on 25/03/2017 13:00
ZonedDateTime start = ZonedDateTime.of(2017, 3, 25, 13, 0, 0, 0, london);
// ends on 26/03/2017 02:00
ZonedDateTime end = ZonedDateTime.of(2017, 3, 26, 2, 0, 0, 0, london);
// get the difference in hours
System.out.println(ChronoUnit.HOURS.between(start, end)); // 12
// get the duration in hours
Duration duration = Duration.between(start, end);
System.out.println(duration.toHours()); // 12
// using until() method
System.out.println(start.until(end, ChronoUnit.HOURS)); // 12
All the three methods above (ChronoUnit.HOURS.between()
, duration.toHours()
and start.until()
) return 12
. According to javadoc, between
and until
are equivalent, as the first just internally calls the second. Using a Duration
is also equivalent, as it uses the nanoseconds between them and convert it to hours.
- You should use TimeZone ID e.g., "Europe/London"
- Convert start and end time into GMT
- Now find the duration from GMT start and end times
Daylight is automatically handled when u use TimeZone IDs.
来源:https://stackoverflow.com/questions/44617846/duration-with-daylight-saving