LocalDate formatter bug? [duplicate] - java

This question already has answers here:
Y returns 2012 while y returns 2011 in SimpleDateFormat
(5 answers)
How does Java "week year" really work?
(2 answers)
Closed 3 years ago.
I found strange behaviour when using Java's DateTimeFormatter on LocalDate for 30th and 31st of December.
LocalDate date1 = LocalDate.of(2019, Month.DECEMBER, 30);
System.out.println("date1: " + date1);
System.out.println("converted date1: " + DateTimeFormatter.ofPattern("YYYY-MM-dd").format(date1));
LocalDate date2 = LocalDate.of(2019, Month.JANUARY, 30);
System.out.println("date2: " + date2);
System.out.println("converted date2: " + DateTimeFormatter.ofPattern("YYYY-MM-dd").format(date2));
Output:
date1: 2019-12-30
converted date1: 2020-12-30
date2: 2019-01-30
converted date2: 2019-01-30
The first date (December 30) is converted with the next year, the second date (January 30) is converted with the correct year.
Am I missing something out, or is it a bug?

Y means "year of week-based year". It's not the same as y which means "year of era" as per docs.
This post explains the difference and purpose of Y:
A week year is a year where all the weeks in the year are whole weeks. This is specified by some standard (which I don't remember at the moment). Basically, this guarantees that a program working on a week's data will not transition between years. Unfortunately, this also means that the beginning of the year may not start on the first of January. What year a particular day belongs in depends on these rules, and of course, there are days where the year and the week year are different.
In your example 30st Dec '19 was a Monday, 31st Dec '19 was a Tuesday and 1st Jan '20 was Wednesday so "year of week-based year" for this three days is 2020.

Change 'Y' to 'y' (Capital case to lower case) 'Y' is week based year and since most of the week of Dec-30, 2019 falls into 2020 the year is 2020. while lower case 'y' is your regular year. See JavaDoc for DateTimeFormatter for details

Related

DateFormatter ofPattern not returning the correct date [duplicate]

This question already has answers here:
Cant parse recently formatted ZonedDateTime Java 8
(1 answer)
Java LocalDate Formatting of 2000-1-2 error [duplicate]
(2 answers)
Difference between year-of-era and week-based-year?
(7 answers)
Closed 4 years ago.
I am using DateTimeFormatter to format my LocalDate which has the value 31 Jan 2019.
When I execute the code below, the correct date is returned:
// 31, Dec, 2018
System.out.println(LocalDate.now().minusMonths(1).format(DateTimeFormatter.ofPattern("dd, MMM, yyyy")));
But if I execute the code below, the date is returned with the correct date, month but the wrong year:
// 31, Dec, 2019
System.out.println(LocalDate.now().minusMonths(1).format(DateTimeFormatter.ofPattern("dd, MMM, YYYY")));
What I am confused about is that, if I also use the same pattern above and I just minusDays(30) which makes my expected to be 01 Dec 2018, the correct result is returned:
// 01, Dec, 2018
System.out.println(LocalDate.now().minusMonths(1).minusDays(30).format(DateTimeFormatter.ofPattern("dd, MMM, YYYY")));
Could using YYYY in the DateTimeFormatter.ofPattern("dd, MMM, YYYY")) pattern because this?
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
class Example {
public static void main(String[] args) {
/*Today's date is 31st of January 2019*/
// 2018-12-31
System.out.println(LocalDate.now().minusMonths(1));
// 31, Dec, 2018
System.out.println(LocalDate.now().minusMonths(1).format(DateTimeFormatter.ofPattern("dd, MMM, yyyy")));
// 31, Dec, 2019
System.out.println(LocalDate.now().minusMonths(1).format(DateTimeFormatter.ofPattern("dd, MMM, YYYY")));
// 01, Dec, 2018
System.out.println(LocalDate.now().minusMonths(1).minusDays(30).format(DateTimeFormatter.ofPattern("dd, MMM, YYYY")));
// 31, Dec, 2018
System.out.println(LocalDate.now().minusMonths(1).format(DateTimeFormatter.ofPattern("dd, MMM, uuuu")));
}
}
As far as I understood reading the documentation is because of this:
"YY" specifies the week-based year numbering and for normal year numbering, you should use "yy" instead.
https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html
EDIT:
The week and year numbering in an ISO-8601 calendar is different from a standard Gregorian calendar. Here’s how January 2nd, 2011 would be represented:
Calendar System Week Number Year Number
Standard Gregorian 1 2011
ISO-8601 52 2010
The Gregorian leap cycle, which has 97 leap days spread across 400 years, contains a whole number of weeks (20871). In every cycle there are 71 years with an additional 53rd week (corresponding to the Gregorian years that contain 53 Thursdays). An average year is exactly 52.1775 weeks long; months (​1⁄12 year) average at exactly 4.348125 weeks.
An ISO week-numbering year (also called ISO year informally) has 52 or 53 full weeks. That is 364 or 371 days instead of the usual 365 or 366 days. The extra week is sometimes referred to as a leap week, although ISO 8601 does not use this term.
For more info: https://en.wikipedia.org/wiki/ISO_week_date

Why Java calender object return wrong WEEK_OF_YEAR and WEEK_OF_MONTH

By the following way I set date object to calendar instance.
But when I get the week of year , wrongly it returns week of the year as 1.
Same as week of the year, week of the month value also wrong. It return as 6. But it should be 5.
Following is output of calendar instance value
java.util.GregorianCalendar[time=1514678400000,
areFieldsSet=true,
areAllFieldsSet=true,
lenient=true,
zone=sun.util.calendar.ZoneInfo[id="UTC",
offset=0, dstSavings=0, useDaylight=false, transitions=0, lastRule=null],
firstDayOfWeek=1, minimalDaysInFirstWeek=1, ERA=1, YEAR=2017, MONTH=11, WEEK_OF_YEAR=1, WEEK_OF_MONTH=6, DAY_OF_MONTH=31, DAY_OF_YEAR=365, DAY_OF_WEEK=1, DAY_OF_WEEK_IN_MONTH=5, AM_PM=0, HOUR=0, HOUR_OF_DAY=0, MINUTE=0, SECOND=0, MILLISECOND=0, ZONE_OFFSET=0, DST_OFFSET=0]
firstDayOfWeek=1 means that Sunday is the first day of the week. So Sunday December 31, 2017 belonged to week 1 of 2018.
It’s not well documented, but it turns out that the week of month follows the month, so on Dec 31, it gives you the number of the week in December. Since December 1 and 2 were Friday and Saturday, they formed week 1 of December. Week 2 began on December 3. So week 6 began on December 31 and lasted only that day. This explains why week of month is 6 in your case.
Whether we use IST time zone (I am assuming it means Asia/Kolkata) or UTC doesn’t make a difference. At 5:30 AM in India, it was 00:00 in UTC, the date was still December 31, and therefore the week numbers are also unchanged.
Your Calendar’s settings of first day of week and minimal days in first week follow the standard used in USA and some other countries. If instead you wanted the international standard where Monday is the first day of the week and there is a minimum of 4 days in week one, you may instantiate it with a locale of a country that uses the international standard, for example:
Calendar c = Calendar.getInstance(Locale.FRANCE);
In this case week of year will be 52 and week of month will be 4. Not 5. This is because the first three days of December are not enough to form a week, so week 1 of December begins on December 4. Then the first three days of December are in week 0.
Prefer to use java.time
All of that said, the Calendar class is long outmoded and poorly designed. I recommend you use java.time, the modern Java date and time API, instead. Specifically, the LocalDate & WeekFields classes.
For example:
LocalDate date = LocalDate.of(2017, Month.DECEMBER, 31);
System.out.println("ISO week of year " + date.get(WeekFields.ISO.weekOfWeekBasedYear()));
System.out.println("ISO week of month " + date.get(WeekFields.ISO.weekOfMonth()));
System.out.println("US week of year " + date.get(WeekFields.SUNDAY_START.weekOfWeekBasedYear()));
System.out.println("US week of month " + date.get(WeekFields.SUNDAY_START.weekOfMonth()));
Output:
ISO week of year 52
ISO week of month 4
US week of year 1
US week of month 6
The results agree with those we got from Calendar.
Link: Oracle tutorial: Date Time explaining how to use java.time.

Java - get the same weekly date range for the previous year

I need to obtain certain data for current week and the same week of the previous year based on the current date.
For example, today is 23/11/2017 - Thursday.
I have the next date range for current week: 20/11/2017 (Monday) - 23/11/2017 (Thursday).
What is the best way to obtain a corresponding weekly date range for the previous year ( 21/11/2016 (Monday) - 24/11/2016 (Thursday) )?
You must make a specification document, which the business side should affirm.
Today is 23/11/2017 - Thursday. So the current week is: 20/11/2017
(Monday) - 26/11/2017 (Sunday).
In the previous year we take today 23/11/2017 and subtract a year..
That is a Wednesday 23/11/2016.
We obtain the week: 21/11/2016 (Monday) - 27/11/2016 (Sunday).
A. Irregularity: 29th of February becomes the 28th in the previous
year.
B. We are interested only in Monday - Thursday of the result,
but do all, so we can work on Saturday as well.
Then consider weeks & week numbers. Alternative:
Today is 23/11/2017 - Thursday. This is the week with week number 47,
with week year 2017. (01/01/2017 would be in week 52 of week year
2016). Yield week 47 of previous week year 2016.
A. 53 possibly becomes 52 if there is no week 53.
B. Start of January
can be of the previous week year.
As you see, one should not simply implement, but document such business logic.
By the way the new java date time API is great.
The hard parts are defining what you want and which time zone you want it in. The latter is true because at time of writing it is November 23 in Smolensk, but in other places in the world it is already November 24, so you need to decide.
I understand your problem this way, please check if correct: Find the date range from the beginning of this week (Monday) till today. Then find a range last year also from Monday till the same day of week as today, as close as possible to the same dates. This means that you will always want to go 52 weeks back. Then you will get dates that are one day later (two days later if crossing February 29 in a leap year), this will always be as close as you can get.
With java.time, the modern Java date and time API, the code is simple:
LocalDate today = LocalDate.now(ZoneId.of("Europe/Moscow"));
LocalDate firstDayOfWeek
= today.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
System.out.println("This year: " + firstDayOfWeek + " - " + today);
LocalDate firstDayLastYear = firstDayOfWeek.minusWeeks(52);
LocalDate correspondingDayLastYear = today.minusWeeks(52);
System.out.println("Last year: " + firstDayLastYear + " - "
+ correspondingDayLastYear);
Running just now this printed:
This year: 2017-11-20 - 2017-11-23
Last year: 2016-11-21 - 2016-11-24
Please substitute your desired time zone instead of Europe/Moscow if this is not the one you want.
If you want to print the day of week too, use a DateTimeFormatter.
DateTimeFormatter dateFormatter = DateTimeFormatter
.ofPattern("d/M/uuuu (EEEE)", Locale.forLanguageTag("ru"));
System.out.println("This year: " + firstDayOfWeek.format(dateFormatter) + " - "
+ today.format(dateFormatter));
This prints:
This year: 20/11/2017 (понедельник) - 23/11/2017 (четверг)
If you run the code on December 31, 2018, you will not reach back into 2017:
This year: 2018-12-31 - 2018-12-31
Last year: 2018-01-01 - 2018-01-01
Again, check if this is what you want.

Java SimpleDateFormat shifts Date by one year [duplicate]

This question already has answers here:
Y returns 2012 while y returns 2011 in SimpleDateFormat
(5 answers)
Closed 7 years ago.
I'm getting very weird results, which I can not understand.
public class Test {
private static DateFormat df = new SimpleDateFormat("dd.MM.YYYY HH:mm");
public static void main(String[] args) {
Date d = new Date(1356912000000L);
System.out.println(d);
System.out.println(df.format(d));
}
}
Gives the output:
Mon Dec 31 01:00:00 CET 2012
31.12.2013 01:00
I assume that this might be some issues with locales, but that's a shift by a whole year ! May anyone explain why it performs this way ?
YYYY is the week-year, not the calendar year. You want yyyy instead. Here's Java's relevant details:
Week Of Year and Week Year
Values calculated for the WEEK_OF_YEAR field range from 1 to 53. The
first week of a calendar year is the earliest seven day period
starting on getFirstDayOfWeek() that contains at least
getMinimalDaysInFirstWeek() days from that year. It thus depends on
the values of getMinimalDaysInFirstWeek(), getFirstDayOfWeek(), and
the day of the week of January 1. Weeks between week 1 of one year and
week 1 of the following year (exclusive) are numbered sequentially
from 2 to 52 or 53 (except for year(s) involved in the
Julian-Gregorian transition).
The getFirstDayOfWeek() and getMinimalDaysInFirstWeek() values are
initialized using locale-dependent resources when constructing a
GregorianCalendar. The week determination is compatible with the ISO
8601 standard when getFirstDayOfWeek() is MONDAY and
getMinimalDaysInFirstWeek() is 4, which values are used in locales
where the standard is preferred. These values can explicitly be set by
calling setFirstDayOfWeek() and setMinimalDaysInFirstWeek().
A week year is in sync with a WEEK_OF_YEAR cycle. All weeks between
the first and last weeks (inclusive) have the same week year value.
Therefore, the first and last days of a week year may have different
calendar year values.
For example, January 1, 1998 is a Thursday. If getFirstDayOfWeek() is
MONDAY and getMinimalDaysInFirstWeek() is 4 (ISO 8601 standard
compatible setting), then week 1 of 1998 starts on December 29, 1997,
and ends on January 4, 1998. The week year is 1998 for the last three
days of calendar year 1997. If, however, getFirstDayOfWeek() is
SUNDAY, then week 1 of 1998 starts on January 4, 1998, and ends on
January 10, 1998; the first three days of 1998 then are part of week
53 of 1997 and their week year is 1997.
Instead of:
"dd.MM.YYYY HH:mm"
Use:
"dd.MM.yyyy HH:mm"

SimpleDateFormat("dd-MMM-YYYY") printing year one year ahead [duplicate]

This question already has answers here:
Y returns 2012 while y returns 2011 in SimpleDateFormat
(5 answers)
Closed 8 years ago.
I am using SimpleDateFormat("dd-MMM-YYYY") in my code, which is giving wrong output.
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MMM-YYYY");
System.out.println("Actual date : "+new Date()+" after Formatting : "+ dateFormat.format(new Date()));
above code is giving :
Actual date : Tue Dec 30 13:51:06 IST 2014 after Formatting : 30-Dec-2015
Above code is print date having Year as 1 year ahead.
and this issue is replicable for 28-31 december 2014 dates only.
Thanks in advance.
--Ajay
You're using YYYY, which is the "ISO-8601 week year". That should almost always be used in conjunction with w, "week in year". You want yyyy to show the normal calendar year.
The reason they're different is that the first ISO-8601 week of a year is the first (Monday to Sunday) week that includes at least 4 days. This means that the first week of the year is the one containing the first Thursday. As January 1st 2015 falls on a Thursday, that means that the week of 2014-12-29 to 2015-01-04 is all "week year 2015, week of year 1". (I'm surprised if you see if for December 28th...)
In other years, the first few days of the year are in week 52 or 53 of the previous year. For example, January 1st 2010 was in week 53 of week-year 2009, and January 1st 2011 was in week 52 of week-year 2010.

Categories