I need to write one function which will create the future installments for the invoice. Below is the function which creates the list of future installment dates :-
public List<Date> getInstallmentDates(Invoice objectWithInvoiceDateField, int noOfInstallments, String instFreq)
{
//objectWithInvoiceDateField.getInvoiceDate this will return java.util.Date instance
ZonedDateTime invoiceDate = objectWithInvoiceDateField.getInvoiceDate.toInstant().atZone(ZoneId.systemDefault());
ZonedDateTime firstInstallment = ZonedDateTime.of( invoiceDate.getYear(), invoiceDate.getMonthValue() , invoiceDate.getDayOfMonth() , 0 , 0 , 0, 0 , ZoneId.systemDefault());
List<Date> installmentDates = new ArrayList();
installmentDates.add(Date.from(firstInstallment.toInstant()));//First Installment
/*Code for the subsequent installments*/
for (int i = 1; i < noOfInstallments; i++) {
ZonedDateTime subsequentInstallments = null;
if(instFreq.equalsIgnoreCase("Quarterly")) {
subsequentInstallments = firstInstallment.plusMonths(3*i);
}
else if(instFreq.equalsIgnoreCase("Semi-annual")){
subsequentInstallments = firstInstallment.plusMonths(6*i);
}
else
subsequentInstallments = firstInstallment.plusMonths(i);
installmentDates.add(Date.from(subsequentInstallments.toInstant()));
}
return installmentDates;
}
This works as expected except for the last iteration. Below is the output if I run this method from main method for
getInstallmentDates(invoice, 5, "Monthly");
Thu Jul 30 00:00:00 EDT 2020
Sun Aug 30 00:00:00 EDT 2020
Wed Sep 30 00:00:00 EDT 2020
Fri Oct 30 00:00:00 EDT 2020
Mon Nov 30 00:00:00 ***EST*** 2020
Can some one please help me understand why the timezone for last instance is changed to EST ?
Thanks in advance!
Presumably because you have used the timezone to be ZoneId.systemDefault(), and your system defaults to a timezone that honours daylight saving time. Assuming EDT is Eastern Daylight Time and EST is Eastern Standard Time, in 2020 the end of daylight saving happens on 1 November and therefore the timezone name changes.
Related
We faced following problem:
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy", java.util.Locale.GERMAN);
String dateInString = "06-04-1980";
Date date = formatter.parse(dateInString);
before: Sun Apr 06 00:00:00 CEST 1980
after: Sun Apr 06 01:00:00 CEST 1980
Another example:
Date date = Date.from(LocalDate.of(1980, 4, 6).atStartOfDay(ZoneId.systemDefault()).toInstant());
Facing the same problem.
We thought change of java11 to java17 is the problem, but it wasn't. It was the change of the timezone from Europe/Berlin to Europe Vienna. On 1980-04-06 the daylight saving time was established in Austria and the change of the hour was at 00:00. So there was no 00:00 at this date.
Reproduceable example - changing timezone to "Europe/Berlin" results in 0 hour.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
for (LocalDate date = LocalDate.of(1500, 04, 01); date.isBefore(LocalDate.of(9999, 1, 1)); date = date.plusDays(1)) {
Date out = Date.from(date.atStartOfDay(ZoneId.of("Europe/Vienna")).toInstant());
Calendar cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getTimeZone(ZoneId.of("Europe/Vienna")));
cal.setTime(out);
if (cal.get(Calendar.HOUR_OF_DAY) > 0) {
System.out.println(date.format(formatter) + " > " + cal.get(Calendar.HOUR_OF_DAY));
}
}
System.out.println("done");
All dates before 1893-03-31 have 23 as hour in timezone "Europe/Vienna", in "Europe/Berlin" its also 0.
It's not really a problem, it's a special thing about timezone "Europe/Vienna" which was changed in our system. If you get this problem, check your timezone, maybe it was changed by some other properties.
While summer time (DST) started at 02:00 o’clock in Germany on that date, it started already at midnight in Austria (Europe/Vienna time zone), so the time 00:00 did not exist, which is why we suddenly got 01:00. Both time zones are printed as CEST (Central European Summer Time), so the abbreviation does not allow us to distinguish.
I am in Israel, so in order to simulate the time zone of central Europe (using Java 17), I set the [System] property user.timezone to CET using the -D option of the java command. Then I ran the following code:
/*
* import java.time.ZoneId;
* import java.time.ZonedDateTime;
* import java.util.Date;
*/
ZonedDateTime zdt = ZonedDateTime.of(1980, 4, 6, 0, 0, 0, 0, ZoneId.systemDefault());
System.out.println(Date.from(zdt.toInstant()));
The result I got was:
Sun Apr 06 00:00:00 CET 1980
This is the result that you want, correct?
We have a requirement in java to validate the local time before it is passed to scheduler like quartz. System receives London local time say 01:30 AM but this time in not valid on March 26 2017 (daylight savings).
How do I write a code to output below results?
Input
12:30, 01:30, 02:30
Output
Mar 26 2017 12:30 -> Valid, GMT
Mar 26 2017 01:30 -> Invalid, NA
Mar 26 2017 02:30 -> Valid, BST
Assuming that you start with a LocalDateTime then you can test to see if it's valid for scheduling by seeing if a given timezone reports that there are valid offsets for the time. This info is available in the ZoneRules class.
Here's some sample code:
#Test
public void test() throws Exception {
TimeZone tz = TimeZone.getTimeZone("Europe/London");
ZoneId londonZone = tz.toZoneId();
String springAhead = "2017-03-26T01:30";
assertFalse(isValidForScheduling(londonZone, LocalDateTime.parse(springAhead)));
String fallBack = "2017-10-29T01:30";
assertFalse(isValidForScheduling(londonZone, LocalDateTime.parse(fallBack)));
}
private boolean isValidForScheduling(ZoneId zoneId, LocalDateTime ldt) {
ZoneRules rules = zoneId.getRules();
List<ZoneOffset> validOffsets = rules.getValidOffsets(ldt);
return validOffsets.size() == 1;
}
If the list of validOffsets is empty then it's not a valid time. If there is more than 1 entry then the time occurs multiple times in that zone (the case of putting the clocks back). If there's a single entry, then it's a regular time.
You'd probably want to fail on an empty list and warn on a list with multiple entries.
The below code errors only for March 26 2017 1AM-2AM. I didnt like the way it is written. Can it be refactored? This doesn't error on Oct 29 2017.
LocalDateTime localDateTime = LocalDateTime.of(2017, 3, 26, hours, minutes);
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.of("Europe/London"));
if ( zonedDateTime.getHour() != localDateTime.getHour() ) {
System.out.println("MISMATCH!!!");
}
I just found a strange behavior with the JAVA Calendar Class.
When I set the minutes to 0 the result differs depending on the used TimeZone.
Does anyone know why?
Example Code
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class CalendarTest {
public static void main(String[] args) {
Date date = new Timestamp(1477780200000L);
System.out.println(date); // 2016-10-30 00:30:00.0
testMethod(date, Calendar.getInstance(TimeZone.getTimeZone("CET"))); // Sun Oct 30 02:00:00 CET 2016
testMethod(date, Calendar.getInstance(TimeZone.getTimeZone("GMT+1"))); // Sun Oct 30 02:00:00 CEST 2016
}
private static void testMethod(Date date, Calendar c) {
c.setTime(date);
c.add(Calendar.HOUR_OF_DAY, 2);
c.set(Calendar.MINUTE, 0);
System.out.println(c.getTime());
}
}
edit (to make my question more understandable):
changed testMethod
this changed Method calculates in BOTH(!) cases Sun Oct 30 02:30:00 CEST 2016.
private static void testMethod(Date date, Calendar c) {
c.setTime(date);
c.add(Calendar.HOUR_OF_DAY, 2);
System.out.println(c.getTime());
}
You can see in the example code below that displayed date is rather different than real time (in milliseconds). The problem is that Sun Oct 30 02:00:00 CET 2016 exists both in CET and CEST time zone. When switching CEST => CET you are going back one hour (producing hour overlap). For Calendar object, this is very tricky because you are expressing time change in the selected time zone. When you want to reset minutes in this very specific, Calendar have to discover in which time zone you are expressing the change.
I'm not 100% how Calendar is handling this but in first example CET, you specifically suggesting that you want to use CET. Therefore, when overlapping takes place Calendar can select your suggestion (CET). When you are using GMT to express it then Calendar have to pick one of the time zones CET or CEST and is selecting CEST.
public static void main(String[] args) {
Date date = new Timestamp(1477780200000L);
System.out.println(date); // 2016-10-30 00:30:00.0
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("CET"));
calendar.setTime(date);
print(1, calendar); // 1: Sun Oct 30 00:30:00 CEST 2016 | 1477780200000
calendar.add(Calendar.HOUR_OF_DAY, 2);
print(2, calendar); // 2: Sun Oct 30 02:30:00 CEST 2016 | 1477787400000
calendar.set(Calendar.MINUTE, 0); // minutes expressed in CET
print(3, calendar); // 3: Sun Oct 30 02:00:00 CET 2016 | 1477789200000
System.out.println("--");
calendar = Calendar.getInstance(TimeZone.getTimeZone("CET"));
calendar.setTime(date);
print(4, calendar); // 4: Sun Oct 30 00:30:00 CEST 2016 | 1477780200000
calendar.add(Calendar.HOUR_OF_DAY, 2);
print(5, calendar); // 5: Sun Oct 30 02:30:00 CEST 2016 | 1477787400000
calendar.set(Calendar.MINUTE, 0); // minutes expressed in CET
print(6, calendar); // 6: Sun Oct 30 02:00:00 CET 2016 | 1477789200000
System.out.println("--");
calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+1"));
calendar.setTime(date);
print(4, calendar); // 4: Sun Oct 30 00:30:00 CEST 2016 | 1477780200000
calendar.add(Calendar.HOUR_OF_DAY, 2);
print(5, calendar); // 5: Sun Oct 30 02:30:00 CEST 2016 | 1477787400000
calendar.set(Calendar.MINUTE, 0); // minutes expressed in GMT
print(6, calendar); // 6: Sun Oct 30 02:00:00 CEST 2016 | 1477785600000
}
private static void print(int prefix, Calendar calendar) {
System.out.println(prefix + ": " + calendar.getTime() + " | " + calendar.getTimeInMillis());
}
Update
What is more interesting is the Calendar method getTimeInMillis:
public long getTimeInMillis() {
if (!isTimeSet) {
updateTime();
}
return time;
}
As you can see time is updated when you are getting it! There is a flag isTimeSet which is set to false every time you use set method like calendar.set(Calendar.MINUTE, 0). It means that your time becomes invalid in terms of right timezone/epoch etc. This method just sets the given calendar field to the given value and that's it. Moreover, this method is not doing any additional checks if your setting is valid. add method, on the other hand, respects calendar rules and move your date gracefully.
To summarize. You are setting minutes to 0 which forces calendar to recalculate date. You were right, the set is the problematic one.
Recently New Zealand observed daylight saving on 27 sept 15.
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
sd.setTimeZone(TimeZone.getTimeZone("Pacific/Auckland"));
Date dateValue = sd.parse("2015-09-30");
System.out.println(dateValue); // prints "Tue Sep 29 07:00:00 EDT 2015" My local system timzone in EDT
dateValue = DateUtils.addDays(dateValue, -6); // 6 days back 24 Sep of Pacific/Auckland
System.out.println(dateValue); // prints "Tue Sep 23 07:00:00 EDT 2015"
The second print statement should print Tue Sep 29 08:00:00 EDT 2015, as Daylight Saving not is in effect.
The issue is before 27 Sep 15 NZ = UTC+12
and after NZ = UTC +13
So on date of 23 Sep It should have time 08:00:00 not 07:00:00
The problem is within DateUtils.addDays from Apache Commons: it is using a Calendar with the default timezone to add and subtract days instead of using a user-supplied timezone. You can see this in the source code of the method add: it calls Calendar.getInstance() and not Calendar.getInstance(someTimezone)
If you construct yourself the Calendar and set the correct timezone, the problem disappears:
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
sd.setTimeZone(TimeZone.getTimeZone("Pacific/Auckland"));
Date dateValue = sd.parse("2015-09-30");
System.out.println(dateValue); // prints "Tue Sep 29 13:00:00 CEST 2015"
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("Pacific/Auckland")); // set correct timezone to calendar
calendar.setTime(dateValue);
calendar.add(Calendar.DAY_OF_MONTH, -6);
dateValue = calendar.getTime();
System.out.println(dateValue); // prints "Wed Sep 23 14:00:00 CEST 2015"
also i have used joda api to resolved this timezone issue.
org.joda.time.DateTimeZone timeZone = org.joda.time.DateTimeZone.forID( "Pacific/Auckland" );
DateTime currentDate= new DateTime( new Date(), timeZone );
DateTime dateValue = now.plusDays( -6 ); // prints Tue Sep 29 08:00:00 EDT 2015
I have three different times:
time on server - "Wed, 19 Feb 2014 11:44 CET"
time of start meeting on server - "12:00h"
time on device- "13:49"
I need to get time of start meeting on device ...this-> "14:00h" or time to meeting this-> "11m"
I'm trying to get it by using :
long ts = System.currentTimeMillis();
Date localTime = new Date(ts);
String gmt_time="12:00h";
SimpleDateFormat format = new SimpleDateFormat("HH:mm'h'");
format.setTimeZone(TimeZone.getTimeZone("GMT"));
Date d_date = null;
d_date = format.parse(gmt_time);
format.setTimeZone(TimeZone.getTimeZone("UTC"));
Date fromGmt = new Date(d_date.getTime() + TimeZone.getDefault().getOffset(localTime.getTime()));
String new_date=format.format(fromGmt);
But result in new_date is "15:00h" (I need "14:00h")
You assumption of CET = GMT on Wed, 19 Feb 2014 seems to be incorrect - refer to here.
CET is an hour ahead of GMT
11:44 CET would mean 10:44 GMT
Hence, when you calculate an offset from GMT time and your local time, it adds an hour to it.
Change format.setTimeZone(TimeZone.getTimeZone("GMT")); to format.setTimeZone(TimeZone.getTimeZone("CET")); and it should work as expected.
Found quickly solution
String cet_time="12.11.14"+" "+"12:00h";
SimpleDateFormat format = new SimpleDateFormat("dd.MM.yy' 'HH:mm'h'");
format.setTimeZone(TimeZone.getTimeZone("CET"));
Date d_date = format.parse(cet_time);
( new SimpleDateFormat("dd.MM.yy")).format(fromGmt);//new date String
( new SimpleDateFormat("HH:mm'h'")).format(fromGmt);//new time String