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
Related
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.
I've been trying to convert between Asia/Riyadh to Asia/Amman as a test and the time should still the same as an example, you can check it right here : https://www.timeanddate.com/worldclock/converter.html?iso=20200630T170000&p1=776&p2=214&p3=34&p4=11
this code :
String time = "20:00";
SimpleDateFormat formatter = new SimpleDateFormat("kk:mm");
formatter.setTimeZone(TimeZone.getTimeZone("Asia/Riyadh"));
Date date = formatter.parse(time);
SimpleDateFormat formatter2 = new SimpleDateFormat("kk:mm");
formatter2.setTimeZone(TimeZone.getTimeZone("Asia/Dubai"));
System.out.println(formatter2.format(date));
will output a correct result, from Riyadh to Dubai will be 21:00
but when i try to do it with Amman or Beirut the result is incorrect, the time should remain 20:00, but it comes 19:00 is it something to do with EEST time zones?
Thanks in advance.
If you print date you will see that the date is Jan 1, 1970 and the time zones where different back then.
Change the code to ensure that the date is Jun 30, 2020.
Showing the problem
String time = "20:00";
SimpleDateFormat formatter = new SimpleDateFormat("kk:mm");
formatter.setTimeZone(TimeZone.getTimeZone("Asia/Riyadh"));
Date date = formatter.parse(time);
System.out.println(date);
Output
Thu Jan 01 12:00:00 EST 1970
Fixed using old Date API
String time = "6/30/2020 20:00";
SimpleDateFormat formatter = new SimpleDateFormat("M/d/y kk:mm");
formatter.setTimeZone(TimeZone.getTimeZone("Asia/Riyadh"));
Date date = formatter.parse(time);
System.out.println(date);
SimpleDateFormat formatter2 = new SimpleDateFormat("M/d/y kk:mm z Z");
formatter2.setTimeZone(TimeZone.getTimeZone("Asia/Riyadh"));
System.out.println(formatter2.format(date));
formatter2.setTimeZone(TimeZone.getTimeZone("Asia/Dubai"));
System.out.println(formatter2.format(date));
formatter2.setTimeZone(TimeZone.getTimeZone("Asia/Beirut"));
System.out.println(formatter2.format(date));
formatter2.setTimeZone(TimeZone.getTimeZone("Asia/Amman"));
System.out.println(formatter2.format(date));
Output
Tue Jun 30 13:00:00 EDT 2020
6/30/2020 20:00 AST +0300
6/30/2020 21:00 GST +0400
6/30/2020 20:00 EEST +0300
6/30/2020 20:00 EEST +0300
Fixed using newer Java 8 Time API
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("M/d/u kk:mm");
fmt = fmt.withZone(ZoneId.of("Asia/Riyadh"));
ZonedDateTime zdt = ZonedDateTime.parse(time, fmt);
System.out.println(zdt);
DateTimeFormatter fmt2 = DateTimeFormatter.ofPattern("M/d/u kk:mm z Z");
System.out.println(zdt.format(fmt2.withZone(ZoneId.of("Asia/Riyadh"))));
System.out.println(zdt.format(fmt2.withZone(ZoneId.of("Asia/Dubai"))));
System.out.println(zdt.format(fmt2.withZone(ZoneId.of("Asia/Beirut"))));
System.out.println(zdt.format(fmt2.withZone(ZoneId.of("Asia/Amman"))));
Output
2020-06-30T20:00+03:00[Asia/Riyadh]
6/30/2020 20:00 AST +0300
6/30/2020 21:00 GST +0400
6/30/2020 20:00 EEST +0300
6/30/2020 20:00 EEST +0300
Hi can any one explain why such abnormal behavior from Calendar .after method
Calendar cal = Calendar.getInstance();
Calendar cal1 = Calendar.getInstance();
cal.set(Calendar.HOUR, 14);
cal1.set(Calendar.HOUR, 13);
System.out.println(cal.after(cal1)+" Cal "+cal.getTime()+" cal1 "+cal1.getTime());
cal.set(Calendar.DATE, Calendar.getInstance().get(Calendar.DATE));
System.out.println(cal.after(cal1)+" Cal "+cal.getTime()+" cal1 "+cal1.getTime());
Output:
true Cal Tue Oct 01 02:55:16 IST 2019 cal1 Tue Oct 01 01:55:16 IST 2019
true Cal Wed Oct 30 02:55:16 IST 2019 cal1 Tue Oct 01 01:55:16 IST 2019
but I did not get why cal is after cal1 even if i have set cal1's date to current date,
so if cal is today, I assigned the time as 14 hr it mover to next date then i set the date as current date in cal while for cal1 i did not.
So why still cal.after(cal1) is showing true in second syso while my cal1 is clearly 1 day greater than cal?
any suggestion to resolve such problem? Use java.time
I agree with you that there are some surprises in your code. You may have intended this:
ZoneId zone = ZoneId.of("Asia/Kolkata");
ZonedDateTime zdt = ZonedDateTime.now(zone);
ZonedDateTime zdt1 = ZonedDateTime.now(zone);
zdt = zdt.withHour(14);
zdt1 = zdt1.withHour(13);
System.out.println(zdt.isAfter(zdt1) + " zdt " + zdt + " zdt1 " + zdt1);
zdt = zdt.withDayOfMonth(ZonedDateTime.now(zone).getDayOfMonth());
System.out.println(zdt.isAfter(zdt1) + " zdt " + zdt + " zdt1 " + zdt1);
Output when I ran the code just now:
true zdt 2019-09-30T14:44:13.630029+05:30[Asia/Kolkata] zdt1 2019-09-30T13:44:13.630362+05:30[Asia/Kolkata]
true zdt 2019-09-30T14:44:13.630029+05:30[Asia/Kolkata] zdt1 2019-09-30T13:44:13.630362+05:30[Asia/Kolkata]
I get true both times just as you got from your code, which shouldn’t be surprising. As others have said, 02:55h is after 01:55h, and Oct 30 is after Oct 01. Also, referring to my result, 14:44 is after 13:44. In both lines these two times are compared.
I am using java.time, the modern Java date and time API.
What went wrong in your code?
The surprises in your code stem from the Calendar class being poorly designed and often behaving differently from what we would immediately expect.
Why when you set the hour to 14, you get Tue Oct 01 02:55:16 IST 2019? The date has changed into the following month, and the hour of day is 2, not 14.
Why when you set the date to today’s date, September 30, you get October 30?
For 1., Calendar.HOUR refers to hour within AM or PM from 0 through 11. So setting it to 14 we should have expected an exception. A Calendar with standard settings doesn’t care. Since the time was already in PM, it extrapolates, so 14 PM becomes 2 AM on the next day. Since today is the last day of September, you get October 1.
For 2., Calendar.DATE doesn’t refer to the full date, but to the day of month. Since current day of month is 30 and we already had October1, we get October 30.
Long story short: Avoid the Calendar class. Use ZonedDateTime and/or other classes form java.time, the modern Java date and time API. They are so much nicer to work with and give far fewer surprises like the ones you experienced.
Link
Oracle tutorial: Date Time explaining how to use java.time.
Java docs for - Calendar.after()
public boolean after(Object when) {
return when instanceof Calendar && compareTo((Calendar)when) > 0;
}
//By definition :- true if the time of this Calendar is after the time represented by when; false otherwise.
System.out.println(cal.after(cal1)+" Cal "+cal.getTime()+" cal1 "+cal1.getTime());
//true Cal Tue Oct 01 02:17:46 IST 2019 cal1 Tue Oct 01 01:17:46 IST 2019
cal.set(Calendar.HOUR, 13);
cal1.set(Calendar.HOUR, 14);
System.out.println(cal.after(cal1)+" Cal "+cal.getTime()+" cal1 "+cal1.getTime());
//false Cal Tue Oct 01 01:16:55 IST 2019 cal1 Tue Oct 01 02:16:55 IST 2019
cal.set(Calendar.DATE, Calendar.getInstance().get(Calendar.DATE));
System.out.println(cal.after(cal1)+" Cal "+cal.getTime()+" cal1 "+cal1.getTime());
//true Cal Wed Oct 30 13:17:46 IST 2019 cal1 Tue Oct 01 14:17:46 IST 2019
System.out.println(cal.after(cal1)+" Cal "+cal.getTime()+" cal1 "+cal1.getTime());
//true Cal Tue Oct 01 02:25:19 MMT 2019 cal1 Tue Oct 01 01:25:19 MMT 2019
cal.set(Calendar.DATE, Calendar.getInstance().get(Calendar.DATE));
System.out.println(cal1.after(cal)+" Cal "+cal.getTime()+" cal1 "+cal1.getTime());
//false Cal Wed Oct 30 02:25:19 MMT 2019 cal1 Tue Oct 01 01:25:19 MMT 2019
Using
cal.setTime((Calendar.getInstance()).getTime());
instead of
cal.set(Calendar.DATE, Calendar.getInstance().get(Calendar.DATE));
gives the desired result.
I have wierdo problem with timestamp in Java/Android
Date inputDate = null;
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm dd/MM/yyyy");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
Log.e("DateH:D", hour+" "+day);
try {
inputDate = sdf.parse(hour + " " + day);
Date currentDate = new Date();
Log.e("InputDate", inputDate.toString());
Log.e("InputDate",inputDate.getTime()+"");
Log.e("CurrentDate", currentDate.toString());
Log.e("CurrentDate",currentDate.getTime()+"");
if (!inputDate.after(currentDate) ){
//TODO change this string
hourField.setError("Date from past");
return false;
}
} catch (ParseException e) {
Log.e("DateParser" , e.getLocalizedMessage);
return false;
}
Example output for this is:
DateH:D: 12:33 15/09/16
E/InputDate: Tue Sep 15 14:33:00 CET 16
E/InputDate: -61640134020000
E/InputDate: Tue Sep 15 14:33:00 CET 16
E/CurrentDate: Thu Sep 15 11:38:43 CEST 2016
E/CurrentDate: 1473932323198
So non-timestamp representation of date is correct but timestamp is wrong. How it's possible? What i'm doing wrong?
Use yy to parse 2-digit years.
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm dd/MM/yy");
The getTime method of Date:
Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
represented by this Date object.
Since the year you specified is year 16, the negative result makes sense.
The starting date for epoch milis is Thu, 01 Jan 1970 00:00:00 GMT. Any datetime before that is negative in epoch milis.
this is what i do to get date in java :
Date date = (new GregorianCalendar(year,month - 1, i)).getTime(); // year,month,day
SimpleDateFormat f = new SimpleDateFormat("EEEE");
nameofday = f.format(date);
when i print the date Object it gives me the answer like follows :
Sun Apr 01 00:00:00 IST 2012
Mon Apr 02 00:00:00 IST 2012
Tue Apr 03 00:00:00 IST 2012
Wed Apr 04 00:00:00 IST 2012
Thu Apr 05 00:00:00 IST 2012
Fri Apr 06 00:00:00 IST 2012
Sat Apr 07 00:00:00 IST 2012
from this i want to get only the day ex: 01,02,03,04,05,etc.
How to do this in java?
Regards
Tony
If you want the day as a number, use:
int dayOfMonth = gregorianCalendarInstance.get(Calendar.DATE);
If you want a string like "05", change your date format to dd, that is:
SimpleDateFormat f = new SimpleDateFormat("dd");
Your output is not the nameofday. If you printed nameofday, it would print "saturday" or "friday". If you want the day in the month on two characters, as indicated in the javadoc of SimpleDateFormat, you must use "dd" for the pattern:
Date date = ...
DateFormat df = new SimpleDateFormat("dd");
System.out.println(df.format(date));
You should really learn to read documentation.