Loop a Task for one Year with GregorianCalendar - java

I have to write a program which shows a Timeplan about when to send emails.
The User is inputing a Start date and I have to show the timeplan for one year.
How do I loop the Task?
In this example the mails should be sent every 8 days.
if(recipient==0) {
System.out.println("send mail on this day:" +calendar.getTime());
calendar.add((GregorianCalendar.DAY_OF_YEAR),8);
return true;
}
I would like to loop the System.out.println and the calendar.add task until it is one year later.
edit: I have another case where it should send the emails every 16 days but when the day is a saturday or sunday it should send the mail on the following monday.
I did it like this but now I get more dates than I need.
if(empfaenger==1)
{
for (Date d=startDate; d.before(endDate); d.setTime(d.getTime() + (1000 * 60 * 60 * 24 * 8)))
{
if(calendar.get(calendar.DAY_OF_WEEK)==1)
{
calendar.add((GregorianCalendar.DAY_OF_YEAR),1);
System.out.println("mail will be sent on this day:"+calendar.getTime());
calendar.add((GregorianCalendar.DAY_OF_YEAR), 16);
}
else if(calendar.get(calendar.DAY_OF_WEEK)==7)
{
calendar.add((GregorianCalendar.DAY_OF_YEAR), 2);
System.out.println("mail will be sent on this day:"+calendar.getTime());
calendar.add((GregorianCalendar.DAY_OF_YEAR),16);
}
else
{
System.out.println("mail will be sent on this day:"+calendar.getTime());
calendar.add((GregorianCalendar.DAY_OF_YEAR),16);
}
//System.out.println(calendar.getTime;)
}
}

Here is a sample using java.time api from java 8 , it's much more easier to understand and use compered to calendar or date classes :
static void sendEveryEightDays(){
LocalDateTime timeToSendEmail= LocalDateTime.now();
LocalDateTime afterAYear = timeToSendEmail.plusYears(1);
while(timeToSendEmail.isBefore(afterAYear)){
System.out.println("SendTheEmail "+timeToSendEmail.toString());
timeToSendEmail=timeToSendEmail.plusDays(8);
}
}
if you want to take the user's time zone into consideration you can use ZonedDateTime instated off LocalDateTime :
static void sendEveryEightDays(ZoneId userTimeZone){
ZonedDateTime timeToSendEmail= ZonedDateTime.now(userTimeZone);
ZonedDateTime afterAYear = timeToSendEmail.plusYears(1);
while(timeToSendEmail.isBefore(afterAYear)){
System.out.println("SendTheEmail "+timeToSendEmail.toString());
timeToSendEmail=timeToSendEmail.plusDays(8);
}
}

I wonder why teachers are still teaching the old API (Date, Calendar and SimpleDateFormat), because they have lots of problems and design issues, and they're being replaced by the new APIs. (Java 8 was released in 2014, btw).
Anyway, if you have a GregorianCalendar, you can convert it to the new java.time classes and do the rest with them.
First, you can use the calendar to create an Instant:
Instant instant = Instant.ofEpochMilli(calendar.getTimeInMillis());
The only problem is that, if you create a Calendar and set the day, month and year, it will have the current time (hour/minute/seconds), so the Instant above will have the current time in UTC. If that's ok, you can convert this instant to your timezone:
ZoneId zone = ZoneId.of("America/Sao_Paulo");
ZonedDateTime start = instant.atZone(zone);
I used America/Sao_Paulo, but you can change to the timezone that makes sense to your system. The API uses IANA timezones names (always in the format Region/City, like America/Sao_Paulo or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CST or PST) because they are ambiguous and not standard.
You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds(). You can also use the system's default if you want (ZoneId.systemDefault()), but note that this can be changed without notice, even at runtime, so it's always better to specify which timezone you're using. If you want to work with dates in UTC, you can use the built-in constant ZoneOffset.UTC.
The code above will create a ZonedDateTime with the calendar's date and time adjusted to the specified timezone. Just reminding that, if you do something like this:
Calendar calendar = new GregorianCalendar();
calendar.set(2017, 7, 12);
The date will be equivalent to August 12th 2017 (because months in the Calendar API start at zero, so month 7 is August), and the time will be the current time when the calendar is created.
If you want to specify the hour, you have some options to adjust it:
// change the hour/minute/second to 10:20:45
start = start.with(LocalTime.of(10, 20, 45));
// change just the hour to 10
start = start.withHour(10);
// set to start of the day
start = start.toLocalDate().atStartOfDay(zone);
With this, you can change the time (and also date) fields accordingly. Check the javadoc and Oracle's tutorial to see all the options available. The method atStartOfDay is better because it takes care of Daylight Saving Time changes (depending on DST shift, the day can start at 1AM instead of midnight, and this method takes care of all the details).
If you don't want to rely on Calendar, you can also create the date directly:
// creating August 12th 2017, at 10:00
start = ZonedDateTime.of(2017, 8, 12, 10, 0, 0, 0, zone);
Note that August is month 8 (one of the best and most obvious improvements from the old API).
Now that you have the starting date, you can loop through a whole year and check the dates according to your rules. I'm using the example of sending the email each 16 days and adjust to next monday if it's a weekend:
ZonedDateTime d = start;
// ends in 1 year - this method already takes care of leap years
ZonedDateTime end = start.plusYears(1);
while (end.isAfter(d)) {
d = d.plusDays(16);
if (d.getDayOfWeek() == DayOfWeek.SUNDAY || d.getDayOfWeek() == DayOfWeek.SATURDAY) {
// weekend, adjust to next monday
d = d.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
}
// send email
}
If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes.
The only difference from Java 8 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.
As #BasilBourque reminded me in the comments, you can also convert a GregorianCalendar to a ZonedDateTime using the toZonedDateTime() method (this will use the calendar's timezone - usually the system's default, if you don't set it). You can also convert it to an Instant using the toInstant() method. The only restriction is that those methods are only available in Java 8 (so, if you're using ThreeTen Backport, just use the way it's described above).

Related

How to convert a specific time to milliseconds [duplicate]

This question already has answers here:
How to check if time in day is between two times?
(5 answers)
Closed 5 years ago.
How can I convert one specific hour, e.g. 18:00, to milliseconds?
I need this so that if it's between for example 12:00 and 18:00 I can do something, and if it is not between 12:00 and 18:00 I can do something else.
I get the current time with:
Private long time;
time = System.currentTimeMillis();
But I don't know how to convert an hour to milliseconds.
I searched on the Internet and it seems that if I use System.currentTimeMillis() it will give me the millisecond of the current day and hour but I need it to update for every day something like this:
Today the time in millis is something like this: 1516994140294. But this number contains this: Fri Jan 26 2018 19:15:40. So if I use the millis for 12:00 and 18:00 of this day this means that tomorrow it will not work as I want.
So can you help me with an example or documentation? Everything can help me :) and thanks in advance.
tl;dr
LocalTime.now() // Capture current moment. Better to explicitly pass a `ZoneId` object than rely implicitly on the JVM’s current default time zone.
.isBefore( LocalTime.of( 18 , 0 ) ) // Compare the current time-of-day against the limit.
No need for milliseconds count
No need to count milliseconds. Java has smart date-time classes for this work, found in the java.time package built into Java 8 and later. For earlier Android, see the last bullets below.
No need for System.currentTimeMillis(). The java.time classes do the same job.
LocalTime
To get the current time of day, without a date and without a time zone, use LocalTime.
Determining the current time requires a time zone. For any given moment, the time-of-day varies by zone. If omitted, the JVM’s current default time zone is applied implicitly. Better to explicitly specify your desired/expected time zone, as the default may change at any moment before or during runtime.
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( "Africa/Tunis" ) ;
LocalTime now = LocalTime.now( z ) ;
Compare with methods isBefore, isAfter, and equals.
A shorter way of asking "is equal to or later than noon" is "is not before noon".
boolean isAfternoon =
( ! now.isBefore( LocalTime.NOON ) )
&&
now.isBefore( LocalTime.of( 18 , 0 ) )
;
If you are concerned about the effects of anomalies such as Daylight Saving Time( DST), explore the use of ZonedDateTime instead of mere LocalTime.
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
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….
Split the current time by the ':' delimiter. The first is hours, second is minutes, third is seconds.
Convert the hours to minutes. That is, 18*60.
Add the above answer to the current minutes (18*60 + 00) in this case.
Take the above answer and multiply by 60 for seconds ((18*60 + 00)*60).
Again, take the above, and add your seconds ((18*60 + 00)*60 + 00) in this case.
Again, take the above, multiply by 1000 for milliseconds (((18*60 + 00)*60 + 00)*1000).
Viola, you have your time in milliseconds.
You should take a look at
SimpleDateFormat
There's a good tutorial here
To compare two "dates" you should look at how to create a Calendar (or the more simplified but deprecated Date) object. It implements comparable, so you can convert the current time into a Date object and compare it to known timestamps (like in your question):
Jave Calendar
Java Date
You can set both Calendar and Date to a specific time or the current time. For example Calendar.setCurrentTimeMillis(System.currentTimeMillis()) will get a Calendar instance set the current time (just like Calendar.getInstance()).
Here's an example with Date:
// This is how to get today's date in Java
Date today = new Date();
//If you print Date, you will get un formatted output
System.out.println("Today is : " + today);
//formatting date in Java using SimpleDateFormat
SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd-MM-yyyy");
String date = DATE_FORMAT.format(today);
System.out.println("Today in dd-MM-yyyy format : " + date);
//Another Example of formatting Date in Java using SimpleDateFormat
DATE_FORMAT = new SimpleDateFormat("dd/MM/yy");
date = DATE_FORMAT.format(today);
System.out.println("Today in dd/MM/yy pattern : " + date);
//formatting Date with time information
DATE_FORMAT = new SimpleDateFormat("dd-MM-yy:HH:mm:SS");
date = DATE_FORMAT.format(today);
System.out.println("Today in dd-MM-yy:HH:mm:SS : " + date);
//SimpleDateFormat example - Date with timezone information
DATE_FORMAT = new SimpleDateFormat("dd-MM-yy:HH:mm:SS Z");
date = DATE_FORMAT.format(today);
System.out.println("Today in dd-MM-yy:HH:mm:SSZ : " + date);
From this site: http://www.java67.com/2013/01/how-to-format-date-in-java-simpledateformat-example.html#ixzz55Jw9BaXW

How to change date and fast time

I need to change the time of a date to 23.59.
I can do it but the fast time remain the same so the date is actually not changed.
*start is my starting date exemple 6th december 2017 at 9.31am
Calendar calendar = Calendar.getInstance();
calendar.setTime(start);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE,0);
calendar.set(Calendar.SECOND,0);
start = calendar.getTime();
I have start date at 6th december 2017 at 23.59am but the fast time is still the same.
How can I do?
I recommend you stop using the Calendar class and use java.time, the modern Java date and time API for your task:
ZonedDateTime dateTime = ZonedDateTime.of(
2017, 12, 6, 9, 31, 0, 0, ZoneId.of("Canada/Newfoundland"));
// to change time to 0:00:00
dateTime = dateTime.truncatedTo(ChronoUnit.DAYS);
System.out.println("Changed to 0:00: " + dateTime);
// to change to end of day
dateTime = dateTime.with(LocalTime.MAX);
System.out.println("Changed to end of day: " + dateTime);
// if you need it without seconds
dateTime = dateTime.truncatedTo(ChronoUnit.MINUTES);
System.out.println("Changed to 23:59: " + dateTime);
This prints
Changed to 0:00: 2017-12-06T00:00-03:30[Canada/Newfoundland]
Changed to end of day: 2017-12-06T23:59:59.999999999-03:30[Canada/Newfoundland]
Changed to 23:59: 2017-12-06T23:59-03:30[Canada/Newfoundland]
The classes Date and Calendar are long outmoded. java.time is so much nicer to work with (it is also known as JSR-310).
I recommend you specify explicitly which time zone you want your time in. So fill in yours unless it happens to be Canada/Newfoundland. To use your JVM’s time zone setting use ZoneId.systemDefault(), but beware that this setting may be changed by other parts of your program or other programs running in the same JVM.
In case start is a Date you got from a legacy API that you do not want to change just now, start by converting it to java.time.Instant and do the remainder of your operations from there:
ZonedDateTime dateTime = start.toInstant().atZone(ZoneId.of("Canada/Newfoundland"));
The rest is the same as above. If the opposite was the case, you need to pass a Date to a legacy API at the end, the opposite conversion is:
start = Date.from(dateTime.toInstant());
What went wrong in your code?
There’s is nothing wrong with your code. At least on my computer it behaves as expected. I would be very surprised if it didn’t on yours. A bit of speculation: You may have noticed that the first and the last digits of the value of start.fastTime were the same, and this could have fooled you into thinking the value had not changed. If this was the problem, it may help you to add this line:
calendar.set(Calendar.MILLISECOND, 0);
This will make sure that fastTime ends in at least five zeroes, for example 1513206000000, and it will be more conspicuous that it has changed. Fortunately, the modern API offers the truncatedTo method, an easy way to obtain zeroes on the last places of your milliseconds value.
Links
Oracle tutorial trail: Date Time
Java Specification Request (JSR) 310

Determine if a date is cyber monday in Java

So this sounds easy, just take the day and date in java and see if it's the same day using the system's time with the calendar. This I can do and this would be a question that's probably repeated multiple times on here.
But my question is how to get like Cyber Monday. Let's say I have a program and every year on Cyber Monday he needs to lower the prices in the shop by 70% or set the discount to 70%. (which is actually my goal) Should I use java calendar for it? Which I can I guess. But how should I do it? I can't just check for the day we are now is the same as 27-11-2017 because in 2018 it's not on 27-11-2018. So how should I calculate this or check for it?
Is it possible to use like a API which has annual events and where people can send a request to receive the date of the requested annual event? Like I noticed the google calendar API but this is only for calendars you made yourself. Which I'm not planning to add every annual event for my own.
I made this method, To check if it's CyberMonday, what it's main purpose is. At this moment I'm stuck doing it annually. How can I make this right for every year?
public static void CyberMonday() {
//Check here if it's Cybermonday or if it's day after cybermonday.
if(Server.getCalendar().getYMD().toString().equals("2017/11/27") ) {
Config.CYBER_MONDAY = true;
updateCyberMondayOnWebsite();
} else {
Config.CYBER_MONDAY = false;
}
}
You can use Java 8's new java.time API for that.
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 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.
You can use LocalDate class to get Thanksgiving for a specified year (assuming that it's in US, so it's the fourth Thursday of November), and then get the next Monday after it.
I also use the TemporalAdjusters class, which has built-in methods to get those dates. The code is:
// get Cyber Monday of a specified year
public LocalDate getCyberMonday(int year) {
// Thanksgiving: fourth Thursday of November
// get first day of November
LocalDate d = LocalDate.of(year, 11, 1)
// get the fourth Thursday
.with(TemporalAdjusters.dayOfWeekInMonth(4, DayOfWeek.THURSDAY));
// next monday after Thanksgiving
return d.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
}
With this you can get the Cyber Monday for any year:
// get Cyber Monday for year 2017
LocalDate cyberMonday = getCyberMonday(2017);
So you can compare with another dates:
// checking if today is Cyber Monday
boolean isCyberMonday = cyberMonday.equals(LocalDate.now());
If the date you want to check is a String, you must parse it first (with a DateTimeFormatter) and then compare it.
I'm doing in a generic way: parsing the String, getting the year from it and comparing with the Cyber Monday of that year.
In this example, the date is in the same format of your example (2017/11/27):
String input = "2017/11/27";
// parse the input (in year/month/day format)
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy/MM/dd");
LocalDate parsedDate = LocalDate.parse(input, fmt);
// compare the parsed date with the Cyber Monday of the same year
LocalDate cyberMonday = getCyberMonday(parsedDate.getYear());
boolean isCyberMonday = cyberMonday.equals(parsedDate);
You must change the pattern to match your inputs. Check the DateTimeFormatter javadoc for more information about date patterns.
PS: LocalDate.now() will get the current date in the system's default timezone. If you want to guarantee it gets the current date in a specific timezone, you can do something like LocalDate.now(ZoneId.of("America/New_York")).
Note that I used America/New_York as the timezone: the API uses IANA timezones names (always in the format Region/City, like America/Sao_Paulo or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CST or PST) because they are ambiguous and not standard.
You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds().

How do I add one day to a Calendar object and also account for daylight savings time?

I am trying to create a time limit for objects in a list. This could mean that the objects shelf life could be 23, 24 or 25 hours. Are there any Java libraries that could be useful? This is what I have so far.
My problem is that when I create a record at 9:30 am for example, it must be removed at 9:30 am on the following day. I get discrepancies when it is during the days which DST takes effect. The record is is either deleted at 8:30 or 10:30 depending if I spring forward or backward.
//baseValue = object that I want to check
Date dt = new Date();
Calendar c = Calendar.getInstance();
c.setTime(dt);
c.add(Calendar.DATE, -1);
if(baseValue.getTime() < c.getTime()){
array.remove(baseValue);
}
The old classes (Date, Calendar and SimpleDateFormat) have lots of problems and design issues, including difficulty to deal with DST changes, and they're being replaced by the new APIs.
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.
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 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.
To take care of DST changes, the ideal class is ZonedDateTime, which represents a date and time in a specific timezone. I also use the ZoneId class, which represents the timezone itself.
I'm using my timezone (America/Sao_Paulo), because here we have DST as well, but you can replace with yours (more on that below):
// create a date 1 day before DST change in Sao Paulo, at 9 AM
ZoneId zone = ZoneId.of("America/Sao_Paulo");
ZonedDateTime z = ZonedDateTime.of(2017, 10, 14, 9, 0, 0, 0, zone);
// get the next day, at 9 AM
ZonedDateTime nextDay = z.plusDays(1);
System.out.println(z);
System.out.println(nextDay);
The output is:
2017-10-14T09:00-03:00[America/Sao_Paulo]
2017-10-15T09:00-02:00[America/Sao_Paulo]
Note that the offset changed from -03:00 to -02:00 - it's due to DST starting in São Paulo timezone (clocks move forward 1 hour). But also note that the time (9 AM) was preserved correctly.
If we take the difference in hours, we can see that it's correct:
System.out.println(ChronoUnit.HOURS.between(z, nextDay));
The output is:
23
Which correctly means that 23 hours has passed between those 2 dates (because of clocks shifting 1 hour forward, so 1 hour is "lost").
In your case, you need to know if 1 day has already passed, so you just call:
long days = ChronoUnit.DAYS.between(z, nextDay);
In this case, days will be 1 (even if the difference in hours calculated above is 23, because the API is smart enough to consider DST effects).
So in your case, you just need to check if the difference in days is 1 (or greater than 1, I don't know) and do all that it needs to be done.
If you need to get the current date/time, you can call ZonedDateTime.now(zone).
To use your timezone instead of mine, first note that the API uses IANA timezones names (always in the format Continent/City, like America/Sao_Paulo or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CST or PST) because they are ambiguous and not standard.
You can get a list of timezones names with ZoneId.getAvailableZoneIds() - then choose the one that fits best to your case.
You can also use ZoneId.systemDefault() - it returns the system's default timezone. But this can be changed without notice - even at runtime - so it's recommended to use an explicit timezone.

Java API to get daylight saving boundaries for a year

I have a date range (start and end date) and require to know whether this falls within a Daylight Saving change over.
Is there any Java API available to check this or any Java code to achieve this?
Daylight Saving changes occur at different dates in each country/region, so the first thing to know is the name of the timezone you're checking.
I'm writing this answer using both Joda-Time and the new Java Date/Time API and both use the IANA's list of timezone names (in the format Continent/City). Both API's also avoid to use the 3-letter names because they are ambiguous and not standard.
For the code below I'm gonna use America/Sao_Paulo (the timezone where I live, which has DST changes every year), but you can replace it with the timezone you want.
The code below shows you how to check if a date is in DST and find the next date when a DST change will occur. So, if you have a start and end dates and want to know if both are in within a DST change, you can check if both are in DST or not and also find the next and previous DST changes (and check if the dates are between those changes - it's not clear to me how your check should be done).
Also be aware that Joda-Time is in maintainance mode and is being replaced by the new APIs, so I don't recommend start a new project with it. 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).".
Joda-Time
You can use the org.joda.time.DateTimeZone class. To know all the available timezones, call DateTimeZone.getAvailableIDs().
The code below checks if a date is in DST and also finds the next date when a DST change will occur:
// create timezone object
DateTimeZone zone = DateTimeZone.forID("America/Sao_Paulo");
// check if a date is in DST
DateTime inDst = new DateTime(2017, 1, 1, 10, 0, zone);
// isStandardOffset returns false (it's in DST)
System.out.println(zone.isStandardOffset(inDst.getMillis()));
// check when it'll be the next DST change
DateTime nextDstChange = new DateTime(zone.nextTransition(inDst.getMillis()), zone);
System.out.println(nextDstChange); // 2017-02-18T23:00:00.000-03:00
// check if a date is in DST
DateTime noDst = new DateTime(2017, 6, 18, 10, 0, zone);
// isStandardOffset returns true (it's not in DST)
System.out.println(zone.isStandardOffset(noDst.getMillis()));
// check when it'll be the next DST change
nextDstChange = new DateTime(zone.nextTransition(noDst.getMillis()), zone);
System.out.println(nextDstChange); // 2017-10-15T01:00:00.000-02:00
If you want to find the previous DST change (instead of the next), call previousTransition() instead of nextTransition().
Java new Date/Time API
If you're using Java 8, the new java.time API already comes natively.
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 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 code is very similar to Joda-Time's version. The main differences:
While Joda-Time has isStandardOffset() to check if the date is not in DST, the new API has isDaylightSavings() to check if the date is in DST.
Joda-Time provides the methods directly in the DateTimeZone class, but the new API has a dedicated class to its DST rules (java.time.zone.ZoneRules)
The methods for next and previous transitions return a java.time.zone.ZoneOffsetTransition instead of directly returning a date (this object provides more information about the DST change, as showed below).
Despite all those differences, the idea is very similar:
// create timezone object
ZoneId zone = ZoneId.of("America/Sao_Paulo");
// get the timezone's rules
ZoneRules rules = zone.getRules();
// check if a date is in DST
ZonedDateTime inDST = ZonedDateTime.of(2017, 1, 1, 10, 0, 0, 0, zone);
// isDaylightSavings returns true (it's in DST)
System.out.println(rules.isDaylightSavings(inDST.toInstant()));
// check when it'll be the next DST change
ZoneOffsetTransition nextTransition = rules.nextTransition(inDST.toInstant());
// getInstant() returns the UTC instant; atZone converts to the specified timezone
System.out.println(nextTransition.getInstant().atZone(zone)); // 2017-02-18T23:00-03:00[America/Sao_Paulo]
// you can also check the date/time and offset before and after the DST change
// in this case, at 19/02/2017, the clock is moved 1 hour back (from midnight to 11 PM)
ZonedDateTime beforeDST = ZonedDateTime.of(nextTransition.getDateTimeBefore(), nextTransition.getOffsetBefore());
System.out.println(beforeDST); // 2017-02-19T00:00-02:00
ZonedDateTime afterDST = ZonedDateTime.of(nextTransition.getDateTimeAfter(), nextTransition.getOffsetAfter());
System.out.println(afterDST); // 2017-02-18T23:00-03:00
// check if a date is in DST
ZonedDateTime noDST = ZonedDateTime.of(2017, 6, 1, 10, 0, 0, 0, zone);
// isDaylightSavings returns false (it's not in DST)
System.out.println(rules.isDaylightSavings(noDST.toInstant()));
// check when it'll be the next DST change
nextTransition = rules.nextTransition(noDST.toInstant());
// getInstant() returns the UTC instant; atZone converts to the specified timezone
System.out.println(nextTransition.getInstant().atZone(zone)); // 2017-10-15T01:00-02:00[America/Sao_Paulo]
// you can also check the date/time and offset before and after the DST change
// in this case, at 15/10/2017, the clock is moved 1 hour forward (from midnight to 1 AM)
beforeDST = ZonedDateTime.of(nextTransition.getDateTimeBefore(), nextTransition.getOffsetBefore());
System.out.println(beforeDST); // 2017-10-15T00:00-03:00
afterDST = ZonedDateTime.of(nextTransition.getDateTimeAfter(), nextTransition.getOffsetAfter());
System.out.println(afterDST); // 2017-10-15T01:00-02:00
If you want to find the previous DST change instead of the next, you can call rules.previousTransition() instead of rules.nextTransition().
Certainly there is. There are also more than one. The standard API to use is java.time.
Quite obviously you first need to decide the time zone you want this for.
You tagged your question gmt, and this is easy: GMT does not have daylight saving time (summer time) so there will never be a changeover in your range. If this is what you meant, you need to read no further.
Daylight saving changeover dates are not the same in North America and EU, and on the southern hemisphere they are yet completely different. Also many time zones do not apply DST at all. So get your intended time zone from ZoneId.of(), providing a string in the form continent/city, for example Europe/Stockholm. It accepts a number of cities, I think there’s at least one in every time zone and one in every country. Use ZoneId.getRules() to get a ZoneRules object. Please check the documentation for all the things you can do with this object. I think I would try nextTransistion() passing your start date. If I get a null back, there cannot be a changeover in the range (likely the zone does not apply DST). If I get a ZoneOffsetTransition back, use its getInstant() and check if the Instant lies before your end date.
java.time was described in JSR-310. It is built into Java 8 and later. If you are not yet using Java 8, use the ThreeTen Backport.
You tagged your question jodatime, and yes, Joda-Time should be an option too.
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).
Quoted from the Joda-Time homepage.

Categories