Date using 'YYYY' - java

This is a question related to Java Date year calculation is off by year for two days
I understand the problem appeared from using 'YYYY' instead of 'yyyy', whereby 'YYYY' refers to calendar year instead of the actual year, resulting in the year being wrong if the dates fell onto the first week of January's calendar year.
I tried to read further and understand the problem in
https://docs.oracle.com/javase/9/docs/api/java/util/GregorianCalendar.html#week_year
And it says
"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."
I have been trying to see if there are any time of the year where 01-Jan-XXXX is actually displayed as 01-Jan-(XXXX-1) but have not managed to find any. Is there a case where this may happen?
I did something simple to take string dates and print out using YYYYMMdd format
public static void main(String[] args) throws ParseException
{
Calendar testCalendar = Calendar.getInstance();
System.out.println("First day of the week: " + testCalendar.getFirstDayOfWeek());
System.out.println("Minimal Days in First Week: " + testCalendar.getMinimalDaysInFirstWeek());
SimpleDateFormat YYYYMMdd= new SimpleDateFormat("YYYYMMdd");
String dateString = "01/01/2016";
Date date = new Date();
date = new SimpleDateFormat("dd/MM/yyyy").parse(dateString);
testCalendar.setTime(date);
int week = testCalendar.get(Calendar.WEEK_OF_YEAR);
String date2 = YYYYMMdd.format(date);
System.out.println("Week Number: " + week);
System.out.println("Date: " + date2);
}
And the output was
First day of the week: 1
Minimal Days in First Week: 1
Week Number: 1
Date: 20161231
If I change the date to "01/01/2016"
The output was
First day of the week: 1
Minimal Days in First Week: 1
Week Number: 1
Date: 20160101
So 01/01/2016 is the first week of of 2016, and not week 53 of 2015.

For a concrete answer, the following table shows January 1 for each year from 2010 through 2020 with day-of-week, week-based year and week number in ISO (the international standard) and in the US.
Year DOW ISO US
2010 Fri 2009-53 2010-01
2011 Sat 2010-52 2011-01
2012 Sun 2011-52 2012-01
2013 Tue 2013-01 2013-01
2014 Wed 2014-01 2014-01
2015 Thu 2015-01 2015-01
2016 Fri 2015-53 2016-01
2017 Sun 2016-52 2017-01
2018 Mon 2018-01 2018-01
2019 Tue 2019-01 2019-01
2020 Wed 2020-01 2020-01
As you can see, internationally January 1 regularly falls in week 52 or 53 of the previous year, while in the US it always falls in week 1 of its own year.
International rule: Week 1 is the first one that contains at least 4 days of the new year. In other words, a week belongs in the year where most of its days are. In yet other words, week 1 is the one that holds the first Thursday of the year (since weeks begin on Mondays). This implies that when January 1 is a Friday, Saturday or Sunday, it belongs to the last week of the previous year.
US rule: Week 1 is the week that contains January 1. That January 1 always falls in week 1 of its own year follows from this definition (weeks begin on Sundays).
The table came out of this snippet:
System.out.println("Year DOW ISO US");
for (int year = 2010; year <= 2020; year++) {
LocalDate jan1 = LocalDate.of(year, Month.JANUARY , 1);
System.out.format(Locale.ROOT, "%4d %3s %4d-%02d %4d-%02d%n",
year, jan1.getDayOfWeek().getDisplayName(TextStyle.SHORT_STANDALONE, Locale.ROOT),
jan1.get(WeekFields.ISO.weekBasedYear()), jan1.get(WeekFields.ISO.weekOfWeekBasedYear()),
jan1.get(WeekFields.SUNDAY_START.weekBasedYear()), jan1.get(WeekFields.SUNDAY_START.weekOfWeekBasedYear()));
}
I am of course using java.time, the modern Java date and time API. I warmly recommend it over the outdated Calendar, SimpleDateFormat and Date.

No. The week year is only to be used in conjunction with the week. For example the 1st January 2016 (a Friday) is in the 53. week of 2015. It will never be displayed as 1. January 2015 since that would be ambiguous.
Calendar d = Calendar.getInstance();
d.set(Calendar.YEAR, 2016)
d.set(Calendar.MONTH, Calendar.JANUARY);
d.set(Calendar.DATE, 1);
SimpleDateFormat ft = new SimpleDateFormat("w-YYYY");
ft.format(d.getTime());
// => "53-2015"

In the US, the first week of the year is defined as being the week containing January 1*.
As a consequence, the week-year for January 1 will always be the same as the calendar year, in the US.
*https://en.wikipedia.org/wiki/Week#Week_numbering

Related

Difference between 'yy' and 'YY' in Java Time Pattern [duplicate]

This question already has answers here:
Y returns 2012 while y returns 2011 in SimpleDateFormat
(5 answers)
Why does sdf.format(date) converts 2018-12-30 to 2019-12-30 in java? [duplicate]
(3 answers)
Closed 3 years ago.
From document SimpleDateTimePattern, yy should be the same with YY.
Today is Dec 30, 2019, now we get YY for today is 20, yy for today is 19. What's the difference between yy and YY in Java Time Pattern?
yy is the calendar year, while YY is a week year. A week year can be different from the calendar year depending on which day the first of January falls. For example see ISO-8601 week year.
Today (30 December 2019) is a good example, the calendar year is 2019, but the week year is 2020, because this week is week 1 of 2020. So yy will result in 19, while YY results in 20.
The definition of the first week of a year from the wikipedia page:
The ISO 8601 definition for week 01 is the week with the Gregorian
year's first Thursday in it. The following definitions based on
properties of this week are mutually equivalent, since the ISO week
starts with Monday:
It is the first week with a majority (4 or more) of its days in January.
Its first day is the Monday nearest to 1 January.
It has 4 January in it. Hence the earliest possible first week extends from Monday 29 December (previous Gregorian year) to Sunday 4
January, the latest possible first week extends from Monday 4 January
to Sunday 10 January.
It has the year's first working day in it, if Saturdays, Sundays and 1 January are not working days.
If 1 January is on a Monday, Tuesday, Wednesday or Thursday, it is in
week 01. If 1 January is on a Friday, it is part of week 53 of the
previous year. If it is on a Saturday, it is part of the last week of
the previous year which is numbered 52 in a common year and 53 in a
leap year. If it is on a Sunday, it is part of week 52 of the previous
year.
Some locales, like for example the US, don't follow ISO-8601, because there they use Sunday as the first day of the week, but they have similar rules for week years.
You have it in you link:
y Year Year 1996; 96
Y Week year Year 2009; 09
Week year can be different, for example this new year week, than current year
Week year defines as year's first Thursday:
The first week of the year is the week that contains that year's first Thursday
They both represent a year but yyyy represents the calendar year while
YYYY represents the year of the week.
An example illustrates this much better than words ever could.
package datetest;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Test {
public static void main(String[] args) {
try {
String[] dates = {"2018-12-01", "2018-12-31", "2019-01-01"};
for (String date: dates) {
SimpleDateFormat dt = new SimpleDateFormat("yyyy-MM-dd");
Date d = dt.parse(date);
SimpleDateFormat dtYYYY = new SimpleDateFormat("YYYY");
SimpleDateFormat dtyyyy = new SimpleDateFormat("yyyy");
System.out.println("For date :" + date + " the YYYY year is : " + dtYYYY.format(d) + " while for yyyy it's " + dtyyyy.format(d));
}
} catch (Exception e) {
System.out.println("Failed with exception: " + e);
}
}
}
Output
For date : 2018-12-01 the YYYY year is : 2018 while for yyyy it's 2018
For date : 2018-12-31 the YYYY year is : 2019 while for yyyy it's 2018
For date : 2019-01-01 the YYYY year is : 2019 while for yyyy it's 2019

How to group list of Dates to corresponding week in Java?

I am working on an Android app that will display a list of activities. Every activity (i.e. waling, running) has a property Date (i.e. 9 March 8:58 2017). I have two buttons on the screen - Daily and Weekly and I want to switch betweren the two and change the list accordingly. Now, for the Daily list, I don't have to change anything, since a new Activity is created for every day.
However, I am not sure how to go about the Weekly list. It will essentially calculate stats (adding up the statistics for the individual weeks).
For example, I have a list of dates for the last 50 days. How to distinguish an individual list of Dates that would represent an individual week so I can construct a list of Weeks? Basically, convert those 50 dates into their week equivalent (e.g. about 7 weeks)
This is a test list of Dates that I am trying to get working first:
HashMap<Integer,Date> dateHashMap = new HashMap<>();
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
List<Date> dates = new ArrayList<>();
dates.add(sdf.parse("10/03/2017"));
dates.add(sdf.parse("9/03/2017"));
dates.add(sdf.parse("8/03/2017"));
dates.add(sdf.parse("7/03/2017"));
dates.add(sdf.parse("6/03/2017"));
dates.add(sdf.parse("23/02/2017"));
dates.add(sdf.parse("3/02/2017"));
dates.add(sdf.parse("2/02/2017"));
dates.add(sdf.parse("1/02/2017"));
for(Date d:dates){
dateHashMap.put(d.getDay(),d);
}
System.out.println(dateHashMap.toString());
An example UI design that I am trying to achieve:
As you already have Date property for each activity, then its quite simple actually
First just decide how you want your weeks
ex: I would just go from Mon to Sun as one week
So here Week nth will have dates - 1st to 5th March and Week nth+1 will have 6th to 12th March and so on..
and as far as i can understand you already have every activity (i.e. waling, running) with a property Date (i.e. 9 March 8:58 2017)
So taking an example here (let me know if this isn't how you have your data) :
waling - 1 March 2017 8:58 to 9:58, 3 March 2017 6:20 to 6:50, 8 March 2017 12:00 to 13:00
running - 2 March 2017 6:10 to 8:00, 3 2017 March 7:00 to 8:00, 9 March 2017 5:50 to 7:00
Now data for Week nth you can calculate by adding up duration for waling activity for dates 1st and 3rd March as waling was present only on these dates on Week nth of March 2017 and similarly for week nth+1 and so on
Same goes for running activity for week nth adding up for dates 2nd March, 3rd March and similarly for week nth+1 and so on..
Now you will have something like :
Week nth :
Wailing - 1 hr and 30 min
Running - 2 hrs and 50 min
Week nth+1 :
Wailing - 1 hr
Running - 1 hr and 10 min
And on clicking of each activity you can show some more details..
Hope this helps :)
Edit :
Considering this is how you have your dates list
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
List<Date> dates = new ArrayList<>();
try {
dates.add(sdf.parse("10/03/2017"));
dates.add(sdf.parse("9/03/2017"));
dates.add(sdf.parse("8/03/2017"));
dates.add(sdf.parse("7/03/2017"));
dates.add(sdf.parse("6/03/2017"));
dates.add(sdf.parse("23/02/2017"));
dates.add(sdf.parse("3/02/2017"));
dates.add(sdf.parse("2/02/2017"));
dates.add(sdf.parse("1/02/2017"));
} catch (ParseException e) {
e.printStackTrace();
}
You can create a custom List just to identify the dates that falls in the same week ex (I just used what #Jameson suggested in his answer, you can always write this a lot better):
public List<WeekDay> getListOfWeeksFromListOfDates(List<Date> listOfDates) {
List<WeekDay> listOfWeeks = new ArrayList<>();
WeekDay weekDay;
for (Date date : listOfDates) {
weekDay = new WeekDay(date, new SimpleDateFormat("w").format(date));
listOfWeeks.add(weekDay);
}
return listOfWeeks;
}
public class WeekDay {
Date date;
String weekIdentifier;
public WeekDay(Date Date, String WeekIdentifier) {
this.date = Date;
this.weekIdentifier = WeekIdentifier;
}
public Date getDate() {
return date;
}
public String getWeekIdentifier() {
return weekIdentifier;
}
}
And you can use getListOfWeeksFromListOfDates(dates); to have a list with Dates and Week number, this week number can serve as an identifier to compare the dates and then you can add the activities for dates with same Week number.. Hope you are getting what i am trying to convey here :)
/**
* Gets a list of week numbers (as strings) from a list of dates.
*
* #param listOfDates the list of dates
* #return a list of week in year (as string), corresponding
* one-to-one to the values in the input list.
*/
public List<String> getListOfWeeksFromListOfDates(List<Date> listOfDates) {
List<String> listOfWeeks = new ArrayList<>();
for (Date date : listOfDates) {
listOfWeeks.add(new SimpleDateFormat("w").format(date));
}
return listOfWeeks;
}
Week?
You have not defined what you mean by week.
Do you mean the standard ISO 8601 week where each week starts on a Monday and week # 1 contains the first Thursday, each week numbered 1-52 or 53?
Or do you mean a United States type week beginning on a Sunday with weeks numbered 1-52/53 starting with January 1, and if so are the last days of the previous week in the previous year or the new year?
Or do you mean something else?
Time zone?
What time zone do want to use as the context for determining the date? Or do you want to keep your date-times in UTC like Stack Overflow does in tracking your activity for “today” vs “yesterday”?
Avoid legacy date-time classes
The troublesome old date classes including Date and Calendar should be avoided whenever possible. They are now supplanted by the java.time classes.
Convert your given Date objects to Instant, a moment on the timeline in UTC.
Instant instant = myDate.toInstant();
ISO 8601
I suggest using the standard week whenever possible.
Adjust your Instant into the desired time zone.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
Retrieve the standard week number.
int weekNumber = zdt.get( WeekFields.ISO.weekOfWeekBasedYear() );
Keep in mind that the year number to go with this week number is not the calendar year. We want the year of the week-based year. For example, in some years, December 30 and 31 can belong to the following year number of a week-based year.
int yearOfWeekBasedYear = zdt.get( WeekFields.ISO.weekBasedYear() );
You could track your records against a string composed of this yearOfWeekBasedYear and weekNumber. Use standard format, yyyy-Www such as 2017-W07.
ThreeTen-Extra YearWeek
Instead I suggest you use meaningful objects rather than mere strings. Add the ThreeTen-Extra library to your project to gain the YearWeek class.
This code replaces the WeekFields code we did above.
YearWeek yw = YearWeek.from( zdt );
Thanks to #shadygoneinsane and # Basil Bourque for pointing me to the right direction I solved the problem the following way:
TreeMap<Integer, List<Date>> dateHashMap = new TreeMap<>();
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
List<Date> dates = new ArrayList<>();
dates.add(sdf.parse("10/03/2017"));
dates.add(sdf.parse("9/03/2017"));
dates.add(sdf.parse("8/03/2017"));
dates.add(sdf.parse("7/03/2017"));
dates.add(sdf.parse("6/03/2017"));
dates.add(sdf.parse("23/02/2017"));
dates.add(sdf.parse("3/02/2017"));
dates.add(sdf.parse("2/02/2017"));
dates.add(sdf.parse("1/02/2017"));
for (int i = 0; i < dates.size(); i++) {
List<Date> datesList = new ArrayList<>();
Calendar calendar = Calendar.getInstance();
calendar.setTime(dates.get(i));
int weekOfMonth = calendar.get(Calendar.WEEK_OF_MONTH);
for (Date date : dates) {
Calendar c = Calendar.getInstance();
c.setTime(date);
if (weekOfMonth == c.get(Calendar.WEEK_OF_MONTH)) {
datesList.add(date);
}
}
dateHashMap.put(weekOfMonth, datesList);
}
System.out.println(dateHashMap.toString());
}
And the result:
Output:
1=[Fri Feb 03 00:00:00 GMT 2017,
Thu Feb 02 00:00:00 GMT 2017,
Wed Feb 01 00:00:00 GMT 2017],
2=[Fri Mar 10 00:00:00 GMT 2017,
Thu Mar 09 00:00:00 GMT 2017,
Wed Mar 08 00:00:00 GMT 2017,
Tue Mar 07 00:00:00 GMT 2017,
Mon Mar 06 00:00:00 GMT 2017],
4=[Thu Feb 23 00:00:00 GMT 2017]
Exactly what I needed! So now I can iterate through each week and sum up the statistics and thus formulate the "Weekly" view of the list

Day and month incorrect when setting next day of date using Calendar

//fetch date and convert to date type
String DateString = Integer.toString(getDay()) + "/" + Integer.toString(getMonth()) + "/" + Integer.toString(getYear());
DateFormat parser = new SimpleDateFormat("dd/MM/yyyy"); //current format of date
Date date = (Date) parser.parse(DateString); //convert string to date
//calculate next day
Calendar cal = Calendar.getInstance();
cal.setTime(date); //set calendar time to chosen date
cal.add(Calendar.DATE, 1); //add 1 day to calendar date
//set object to next day
parser.format(cal.getTime()); //set format to dd/MM/yyyy
setDay(cal.get(cal.DAY_OF_MONTH));
setMonth(cal.get(cal.MONTH));
setYear(cal.get(cal.YEAR));
I set a date to 23 October 2002. I want to set it to the next day using the above method. It shows 24 September 2002 instead of 24 October 2002. Why is it adding 1 to the day and removing 1 from the month?
The reason is that months are zero based index ie, they start from 0 instead of 1 so January is 0, Feb is 1, march is 2 and .....Decemeber is 11
From the Oracle docs:
A month is represented by an integer from 0 to 11; 0 is January, 1 is
February, and so forth; thus 11 is December.
EDIT:-
Trying to give the reason for why months start with zero.
The tm structure which is defined in time.h has an integer field tm_mon with the range of 0-11, so I guess this has been taken from the C language. One other reason which might sound wierd but can be reason that since we have names of the month but for days(1,2,3...30,31) we dont have any names

Weeks in month June 2014

Sorry for asking daft question but I cannot get correct number of weeks in June 2014 returned by Calendar:
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.DAY_OF_MONTH, 1);
calendar.set(Calendar.MONTH, Calendar.JUNE);
calendar.set(Calendar.YEAR, 2014);
calendar.setFirstDayOfWeek(Calendar.MONDAY);
System.out
.println("first day of week: " + calendar.getFirstDayOfWeek());
System.out.println("weeks in month: "
+ calendar.getActualMaximum(Calendar.WEEK_OF_MONTH));
System.out.println("days in month: "
+ calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
}
I am getting:
first day of week: 2
weeks in month: 5
days in month: 30
Why number of weeks in June 2014 is not 6? I am using jdk1.8.0_05 on Mac OS X 10.9.3.
The definition of a week depends on what each Locale (country, region, whatever) defines as the first day of the week. You can check that with Calendar#getFirstDayOfWeek(). It also depends on what it considers the minimal days in the first week should be. You can get that with Calendar#getMinimalDaysInFirstWeek(). Your Locale seems to show that it needs more than one day to consider that period a week.
For example, with Locale.CANADA, I get 6 weeks since the getMinimalDaysInFirstWeek() returns 1.

Why Java Calendar set(int year, int month, int date) not returning correct date? [duplicate]

This question already has answers here:
Why is January month 0 in Java Calendar?
(18 answers)
Closed 3 years ago.
According to doc, calendar set() is:
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Calendar.html#set%28int,%20int,%20int%29
set(int year, int month, int date)
Sets the values for the calendar fields YEAR, MONTH, and DAY_OF_MONTH.
code:
Calendar c1 = GregorianCalendar.getInstance();
c1.set(2000, 1, 30); //January 30th 2000
Date sDate = c1.getTime();
System.out.println(sDate);
output:
Wed Mar 01 19:32:21 JST 2000
Why it's not Jan 30 ???
1 for month is February. The 30th of February is changed to 1st of March.
You should set 0 for month. The best is to use the constant defined in Calendar:
c1.set(2000, Calendar.JANUARY, 30);
Months in Calendar object start from 0
0 = January = Calendar.JANUARY
1 = february = Calendar.FEBRUARY
Selected date at the example is interesting. Example code block is:
Calendar c1 = GregorianCalendar.getInstance();
c1.set(2000, 1, 30); //January 30th 2000
Date sDate = c1.getTime();
System.out.println(sDate);
and output Wed Mar 01 19:32:21 JST 2000.
When I first read the example i think that output is wrong but it is true:)
Calendar.Month is starting from 0 so 1 means February.
February last day is 28 so output should be 2 March.
But selected year is important, it is 2000 which means February 29 so result should be 1 March.

Categories

Resources