Java Date year calculation is off by year for two days - java

This caused a Y2K-style bug in my software if you can imagine. Strange thing is the off-by-one year calculation only occurs for two days in the year, which I'm less sure how to troubleshoot.
The output:
03-Jan-2013
02-Jan-2013
01-Jan-2013
31-Dec-2013 ** strange
30-Dec-2013 ** strange
29-Dec-2012
28-Dec-2012
27-Dec-2012
26-Dec-2012
25-Dec-2012
I am not sure which part of the Java date utilities could cause such an error.
The code (since the test is so small I included a complete working program):
import java.util.Calendar;
import java.util.Date;
import java.text.SimpleDateFormat;
public class DateT {
private static String getFormattedBackscanStartTime(int days) {
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MMM-YYYY");
Calendar workingDate = Calendar.getInstance();
workingDate.add(Calendar.DATE, -1 * days);
String formattedStartTime = dateFormat.format(workingDate.getTime());
return formattedStartTime;
}
public static void main(String args[]) {
for(int i = 35; i < 45; i++) {
System.out.println(getFormattedBackscanStartTime(i));
}
}
}

This is the problem:
"dd-MMM-YYYY"
YYYY is the week-year, not the calendar year. You want yyyy instead.
The last two days of calendar year 2012 were in the first week of week-year 2013. You should normally only use the week year in conjunction with the "week of year" specifier (w).

I am assuming you are using java 1.7.
The code snippet above will not work with java 1.6 as SimpleDateFormat("dd-MMM-YYYY") will raise an java.lang.IllegalArgumentException (YYYY is not available in java 1.6)
You need to use yyyy instead of YYYY.
Y -> week-year
y -> year
here
EDIT
Works great with yyyy:
$ java DateT
03-Jan-2013
02-Jan-2013
01-Jan-2013
31-Dec-2012
30-Dec-2012
29-Dec-2012
28-Dec-2012
27-Dec-2012
26-Dec-2012
25-Dec-2012

The problem lies in your date format string - year should be yyyy not YYYY.
If you print the value of workingDate.getTime() in each iteration of the loop, you'll see it has the expected values:
Thu Jan 03 11:19:33 EST 2013
Wed Jan 02 11:19:33 EST 2013
Tue Jan 01 11:19:33 EST 2013
Mon Dec 31 11:19:33 EST 2012
Sun Dec 30 11:19:33 EST 2012
Sat Dec 29 11:19:33 EST 2012
Fri Dec 28 11:19:33 EST 2012
Thu Dec 27 11:19:33 EST 2012
Wed Dec 26 11:19:33 EST 2012
Tue Dec 25 11:19:33 EST 2012
Therefore the problem lies in the SimpleDateFormat usage.

For the sake of completeness, here’s the modern answer using LocalDate (as recommended by Basil Bourque in a comment).
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class DateT {
private static DateTimeFormatter dateFormatter
= DateTimeFormatter.ofPattern("dd-MMM-uuuu", Locale.US);
private static String getFormattedBackscanStartTime(int days) {
return LocalDate.now(ZoneId.systemDefault()).minusDays(days).format(dateFormatter);
}
public static void main(String args[]) {
for(int i = 155; i < 165; i++) {
System.out.println(getFormattedBackscanStartTime(i));
}
}
}
Running this today I got
04-Jan-2017
03-Jan-2017
02-Jan-2017
01-Jan-2017
31-Dec-2016
30-Dec-2016
29-Dec-2016
28-Dec-2016
27-Dec-2016
26-Dec-2016
A few things to note:
Give an explicit locale to your formatter to control the langauge of your output. Even if you just pass Locale.getDefault() you are telling the reader that you have thought about locale and made a decision.
Similarly give an explicit time zone to LocalDate.now() to tell the reader you’ve made a decision (for example ZoneId.of("America/New_York") for a specific time zone; ZoneId.systemDefault() for the JVM’s current time zone setting).
I find the code simpler and more straightforward than the code using the oldfashioned Calendar class. This is typical for the newer classes.
I have used uuuu for year. yyyy (lowercase) works too, there will only be a difference for years before the common era (AKA BC).

You need to use lower case y for the year. Try this:
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MMM-yyyy");

Related

Inconsistent behaviour of GregorianCalendar when created from ZonedDateTime

I'm writing some integration of legacy code that expects date/time as a GregorianCalendar.
So, I'm creating the GregorianCalendar using from(ZonedDateTime) method.
However, the result is showing some inconsistent behaviour when the GregorianCalendar is created from the ZonedDateTime versus when the GregorianCalendar is created, let's say, from a string parsing or even from epoch millis. For example, when setting the Calendar day_of_week. To demonstrate this (https://onecompiler.com/java/3yssz4q86):
import java.util.*;
import java.time.*;
public class Main {
public static void main(String[] args) {
final GregorianCalendar calendarPure = new GregorianCalendar(TimeZone.getTimeZone("America/Los_Angeles"));
printInfo(calendarPure);
ZoneId zone = ZoneId.of("America/Los_Angeles");
final ZonedDateTime zdtNow = ZonedDateTime.now(zone);
final GregorianCalendar calendarFromZdt = GregorianCalendar.from(zdtNow);
printInfo(calendarFromZdt);
final GregorianCalendar calendarFromZdtEpoch = new GregorianCalendar();
calendarFromZdtEpoch.setTimeInMillis(zdtNow.toInstant().toEpochMilli());
printInfo(calendarFromZdtEpoch);
}
private static void printInfo(GregorianCalendar cal) {
System.out.printf("Now: %tc%n", cal);
System.out.printf("Last Sunday: %tc%n", getLastSunday(cal));
System.out.printf("Week of Year: %d%n", cal.get(Calendar.WEEK_OF_YEAR));
System.out.printf("Time in Millis: %d%n", cal.getTimeInMillis());
System.out.printf("toString(): %s%n", cal);
System.out.println();
}
public static GregorianCalendar getLastSunday(GregorianCalendar referenceDate) {
final GregorianCalendar lastSundayMidNight = (GregorianCalendar)referenceDate.clone();
lastSundayMidNight.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
return lastSundayMidNight;
}
}
The output is:
Now: Wed Dec 28 16:45:36 PST 2022
Last Sunday: Sun Dec 25 16:45:36 PST 2022
Week of Year: 53
Time in Millis: 1672274736631
toString(): java.util.GregorianCalendar[time=1672274736631,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/Los_Angeles",offset=-28800000,dstSavings=3600000,useDaylight=true,transitions=185,lastRule=java.util.SimpleTimeZone[id=America/Los_Angeles,offset=-28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2022,MONTH=11,WEEK_OF_YEAR=53,WEEK_OF_MONTH=5,DAY_OF_MONTH=28,DAY_OF_YEAR=362,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=4,HOUR_OF_DAY=16,MINUTE=45,SECOND=36,MILLISECOND=631,ZONE_OFFSET=-28800000,DST_OFFSET=0]
Now: Wed Dec 28 16:45:36 PST 2022
Last Sunday: Sun Jan 01 16:45:36 PST 2023
Week of Year: 52
Time in Millis: 1672274736668
toString(): java.util.GregorianCalendar[time=1672274736668,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/Los_Angeles",offset=-28800000,dstSavings=3600000,useDaylight=true,transitions=185,lastRule=java.util.SimpleTimeZone[id=America/Los_Angeles,offset=-28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2022,MONTH=11,WEEK_OF_YEAR=52,WEEK_OF_MONTH=5,DAY_OF_MONTH=28,DAY_OF_YEAR=362,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=4,HOUR_OF_DAY=16,MINUTE=45,SECOND=36,MILLISECOND=668,ZONE_OFFSET=-28800000,DST_OFFSET=0]
Now: Thu Dec 29 00:45:36 UTC 2022
Last Sunday: Sun Dec 25 00:45:36 UTC 2022
Week of Year: 53
Time in Millis: 1672274736668
toString(): java.util.GregorianCalendar[time=1672274736668,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Etc/UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2022,MONTH=11,WEEK_OF_YEAR=53,WEEK_OF_MONTH=5,DAY_OF_MONTH=29,DAY_OF_YEAR=363,DAY_OF_WEEK=5,DAY_OF_WEEK_IN_MONTH=5,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=45,SECOND=36,MILLISECOND=668,ZONE_OFFSET=0,DST_OFFSET=0]
I noticed that, from GregorianCalendar.toString() that prints the internal fields a different in firstDayOfWeek and minimalDaysInFirstWeek. That could be the cause for the divergence in the after results. I wonder where the GregorianCalendar is getting these values from. Maybe there is a way to set something on ZonedDateTime object that will ensure the results will be the same? Couldn't find anything on javadocs.
Note: Please, don't tell me not to use GregorianCalendar. I know, I know. I'm just writing an integration for two pieces of code that I'm not allowed to modify, one uses GregorianCalendar (sigh), the other uses ZonedDateTime.

Parse Date In Spanish error

Hello Please help me out, I have gone through many questions but didn't get a solution.
Code
String localDate1="Miércoles, 04 Octubre 2017 12:00 PM";
Locale spanishLocale=new Locale("es", "ES");
SimpleDateFormat spanishLocale1=new SimpleDateFormat(getString(R.string.jom_events_date_input_format_12_hrs),spanishLocale);
String dateInSpanish=spanishLocale1.parse(localDate1).toString();
Log.v("###WWW","in Spanish: "+dateInSpanish);
Error
java.text.ParseException: Unparseable date: "Miércoles, 04 Octubre 2017 12:00 PM" (at offset 33)
Just for the record:
You have fortunately posted your error message which points to the offset 33 (that is the position of "PM" in your input). So we can state:
Your problem is related to device-dependent localization data (or OS-dependent), here the concrete data for the Spanish representation of AM/PM. In old versions of CLDR-unicode repository (industry standard as common source for many Java-, C#- or Android distributions), the data "AM" and "PM" were used but in newer versions it uses "a. m." or "p. m." for Spanish.
So in case of mismatch between your input to be parsed (containing "PM") and the real i18n-data you have, I recommend as pragmatic solution string preprocessing:
String input = "Miércoles, 04 Octubre 2017 12:00 PM";
input = input.replace("PM", "p. m.");
// now parse your input with Spanish locale and the appropriate pattern
Please check you spelling on this line
String localDate1="Miércoles, 04 Octubre 2017 12:00 PM";
change October instead of Octubre and also check this Miércoles
You can use this code for your reference::
This code converts:---
miércoles, 04 octubre 2017 12:00 AM
to
Wed Oct 04 00:00:00 IST 2017
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class test {
public static void main(String[] args) throws IOException, ParseException {
//Wednesday, October 4, 2017
String dateInString = "4-Oct-2017";
SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy");
Date date = formatter.parse(dateInString);
SimpleDateFormat formato = new SimpleDateFormat("EEEE, dd MMMM yyyy hh:mm aaaa", new Locale("es", "ES"));
String fecha = formato.format(date);
System.out.println(fecha);
String localDate1 = fecha;
Locale spanishLocale = new Locale("es", "ES");
String pattern = "E, dd MMMM yyyy hh:mm aaaa";
SimpleDateFormat spanishLocale1 = new SimpleDateFormat(pattern, spanishLocale);
String dateInSpanish = spanishLocale1.parse(localDate1).toString();
System.out.println(dateInSpanish);
}
}

java date parsing not working working for month [duplicate]

This question already has answers here:
String to Date conversion returning wrong value
(5 answers)
Closed 5 years ago.
I am trying to find the difference between two dates and I did the following:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class test {
public static void main(String[] args) {
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-DD");
String accessioned = "2017-04-27";
System.out.println(date);
try {
date = format.parse(accessioned);
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println(date);
Date now = new Date();
long diff = now.getTime() - date.getTime();
System.out.println(diff);
if ((diff / (1000 * 60 * 60 * 24)) >= 30) {
System.out.println("haha");
}
}
}
This is the output I get:
Fri Jul 21 14:23:59 CEST 2017
Fri Jan 27 00:00:00 CET 2017
15168239705
haha
The Problem is if I change the the String accessioned for e.g to "2017-04-28" the date changes accordingly, same thing for year but whatever value I put for month, It always outputs January. For e.g in my code it should be April but the output says Jan.
What am I doing wrong?
Change D to d (SimpleDateFormat Doc):
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
D is for day in year (1-365)
d is for day in month (1-31)
Also you can now use LocalDate from Java8 more convenient to use DateTimeFormatter Doc / LocalDate Doc
You apparently want to check if the difference of days is >=30 between your date and now or not, so I'll propose another solution with LocalDate :
LocalDate localDate = LocalDate.parse("2017-04-27", DateTimeFormatter.ofPattern("yyyy-MM-dd"));
long daysDiff = localDate.until(LocalDate.now(), ChronoUnit.DAYS);
System.out.println(daysDiff);
if (daysDiff >= 30){
System.out.println("haha");
}
EDIT : You need to use LocalDateTime instead of LocalDate to be able to use hour/minute/sec also
LocalDateTime localDateTime = LocalDateTime.parse("2017-04-21T11:51:36Z", DateTimeFormatter.ISO_DATE_TIME);
The problem is your date format: new SimpleDateFormat("yyyy-MM-DD")
As listed here, M is already a two-digit format - and D stands for "Day in year", not "Day in month", which is d.
Your format should look like this:
SimpleDateFormat("y-M-d")
...which gives me:
Fri Jul 21 14:44:03 CEST 2017
Thu Apr 27 00:00:00 CEST 2017
7397043764
haha

Java DateFormat issue on Mac vs Windows

I am using the code below on Mac OSX 10.10.2 and it's behaving strangely.
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class StringToDate {
public static void main(String[] args) throws Exception {
String dateInString = "23/Oct/2015";
DateFormat formatter = new SimpleDateFormat("dd/MMM/YYYY");
Date date = formatter.parse(dateInString);
System.out.println(date);
}
}
Output on Mac: Sun Dec 28 00:00:00 CST 2014
Output on Windows: Fri Oct 23 00:00:00 CDT 2015
Why is the Mac output wrong?
Y is for the week year. Use y for the year.
DateFormat formatter = new SimpleDateFormat("dd/MMM/yyyy");
Also, make sure the DateFormat's locale is the right one.
EDIT:
A Date has millisecond precision, so if you want nanosecond precision, you shouldn't use Date and SimpleDateFormat.
S is for milliseconds. Since you tell SimpleDateFormat that the last part of the string is milliseconds, it parses it as that: 545000000 milliseconds (i.e. a bit more than 6 days, which explains the difference between the input and the output).
To get an accurate result, to the millisecond, remove the last 6 characters of the string, and use the pattern "dd-MMM-yyyy-HH.mm.ss.SSS".

Java DateFormat not converting correctly

I am probably overlooking something, but parsing from string to date is not working correctly for me.
I have String: "20110705_060229" which is format: "YYYYddMM_HHmmss"
this piece of code:
Date triggermoment;
public void setTriggermoment(String triggermoment) throws ParseException {
DateFormat formatter = new SimpleDateFormat("YYYYddMM_HHmmss");
this.triggermoment = formatter.parse(triggermoment);
}
gives me as output (when I run toString() method on triggermoment):
Mon Jan 03 06:02:29 CET 2011
Why is it not parsing the day's and month's correctly? It should be June 7 instead of Jan 3.
Thanks in advance!
You have to use y for years. Y is used for week year :
DateFormat formatter = new SimpleDateFormat("yyyyddMM_HHmmss");
Output:
Sat May 07 06:02:29 CEST 2011
It should be June 7 instead of Jan 3
The 5th month in the year is may, not june.
MM is month whereas mm is munutes. y is for year and Y is used for Week year.
Try yyyyddMM_HHmmss instead of YYYYddMM_HHmmss

Categories

Resources