Getting the right day of the week (Java Calendar) - java

I manage some dates in my own date classes. I want to create a method like this in my date:
int getWeekdayIndex()
right now it lookes something like this:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
cal.set(year, month+1, day); // data of this date
int weekdayIndex = cal.get(Calendar.DAY_OF_WEEK);
return weekdayIndex;
I know DAY_OF_WEEK returns 1(Sunday) to 7(Saturday), but if I test this method with
2014-01-06 I get index 5 (suppost to be 2)
2014-01-07 I get index 6 (suppost to be 3)
(I live in Berlin UTC+01:00 - if it matters)

You should use:
cal.set(year, month-1, day); // data of this date
Do note the month-1 part instead of month+1.
Assuming that month's value is:
1 for Jan
2 for Feb
3 for Mar
...

What is month in your scenario? If it's 0 for "January", you are adding 1 when calling the set method. But months in Java are zero-based, so you're setting "February", and February 6th, 2014 is a Thursday (5), and February 7th, 2014 is a Friday (6).
month - the value used to set the MONTH calendar field. Month value is 0-based. e.g., 0 for January.
Try changing
cal.set(year, month+1, day);
to
cal.set(year, month, day);

FYI, Joda-Time 2.3 has convenient methods for such work.
The DateTime class offers a dayOfWeek method. From that you can derive either the localized name of the day, and to your needs, the number. Joda-Time counts days using the international standard ISO 8601, where Monday is 1 and Sunday is 7.
Example code…
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// import org.joda.time.*;
DateTimeZone berlinTimeZone = DateTimeZone.forID( "Europe/Berlin" );
DateTime dateTime = new DateTime( 2013, DateTimeConstants.DECEMBER, 13, 14, 15, 16, berlinTimeZone );
String dayOfWeekAsText = dateTime.dayOfWeek().getAsText( Locale.GERMANY );
int dayOfWeekAsNumber = dateTime.dayOfWeek().get();
System.out.println( "dayOfWeekAsText: " + dayOfWeekAsText );
System.out.println( "dayOfWeekAsNumber: " + dayOfWeekAsNumber );
When run…
dayOfWeekAsText: Freitag
dayOfWeekAsNumber: 5
Easy to jump to another month.
DateTime previousMonthDateTime = dateTime.minusMonths( 1 );
DateTime nextMonthDateTime = dateTime.plusMonths( 1 );

Related

Why is my printed date wrong?

I have verified that the date is read correctly from a file, but once I use SimpleDateFormat.format with the pattern "dd/MM/yy" it suddenly adds a month. This leads me to believe lenient mode is calculating the wrong value. But I have no idea what would make it add a full month.
Some example dates I read:
16/09/2013
23/09/2013
30/09/2013
07/10/2013
14/10/2013
21/10/2013
The code used to parse the date (it's a wrapper around Calendar I made):
public static SimpleDateTime parseDate(String date)
{
String[] dateParts = date.split("[-\\.:/]");
int day = Integer.parseInt(dateParts[0]);
int month = Integer.parseInt(dateParts[1]);
int year = Integer.parseInt(dateParts[2]);
return new SimpleDateTime(dag, maand, jaar);
}
The constructor used here:
public SimpleDateTime(int day, int month, int year)
{
date = Calendar.getInstance();
date.setLenient(true);
setDay(day);
setMonth(month);
setYear(year);
}
The setters for day, month and year:
public void setYear(int year)
{
date.set(Calendar.YEAR, year);
}
public void setMonth(int month)
{
date.set(Calendar.MONTH, month);
}
public void setDay(int day)
{
date.set(Calendar.DAY_OF_MONTH, day);
}
And the code used to format the date:
public String toString(String pattern)
{
String output = new SimpleDateFormat(pattern, Locale.getDefault()).format(date.getTime());
return output;
}
where the pattern passed is:
"dd/MM/yy"
Intended to print a date as:
16/09/13
23/09/13
Instead I get:
16/10/13
23/10/13
January is 0 in Java; February is 1 and so on.
See Calendar.JANUARY, Calendar.FEBRUARY.
So when you're reading 1 from the file
you think you read JAN but you read FEB.
You should do: date.set(Calendar.MONTH, month-1); to fix this.
Months are indexed from 0 not 1 so 10 is November and 11 will be December.
Calendar.MONTH
From documentation:
Field number for get and set indicating the month. This is a calendar-specific value. The first month of the year is JANUARY; the last depends on the number of months in a year.
So if you check JANUARY you see it starts in zero.
Make sure your month is in the interval 0-11. Possibly it is in 1-12.
The reason for this is that the counting starts at 0.
January == 0
February == 1
and so on. See the documentation.
THe problem is that you pass 9 to SimpleDateFormat and since month are indexed from 0 to 11 it will parse month '9' as the 10th month.
You need to subtract 1 from the month :)
Calendar class in Java holds months starting from 0, hence when you set the month as 0, it would consider it as January. SimpleDateFormat provides for a way to correctly display the value as 01.
Calendar cal = Calendar.getInstance();
cal.set(Calendar.MONTH, 0);
System.out.println(new SimpleDateFormat("dd/MM/yy").format(cal.getTime()));
Output:
29/01/14
The workaround for you to align you file that Calendar can work with (since December - or 12 would trickle over to the next year) or modify your logic to pick Constants like:
cal.set(Calendar.MONTH, Calendar.JANUARY);
The answer by peter.petrov is almost correct, except for one major problem. Like your question, it neglects to account for time zone.
For your information, this kind of work is much easier in Joda-Time (or new java.time.* classes in Java 8). Joda-Time is so much cleaner you won't even feel the need to create a wrapper class.
// Specify the time zone for which the incoming date is intended.
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Brussels" );
String input = "16/09/2013";
DateTimeFormatter formatter = DateTimeFormat.forPattern("dd/MM/yyyy").withZone( timeZone );
DateTime dateTime = formatter.parseDateTime( input );
String output = formatter.print( dateTime );
Dump to console…
System.out.println( "dateTime: " + dateTime );
System.out.println( "output: " + output );
System.out.println( "millis since Unix epoch: " + dateTime.getMillis() );
When run…
dateTime: 2013-09-16T00:00:00.000+02:00
output: 16/09/2013
millis since Unix epoch: 1379282400000

Creating java date object from year,month,day

int day = Integer.parseInt(request.getParameter("day")); // 25
int month = Integer.parseInt(request.getParameter("month")); // 12
int year = Integer.parseInt(request.getParameter("year")); // 1988
System.out.println(year);
Calendar c = Calendar.getInstance();
c.set(year, month, day, 0, 0);
b.setDob(c.getTime());
System.out.println(b.getDob());
Output is:
1988
Wed Jan 25 00:00:08 IST 1989
I am passing 25 12 1988 but I get 25 Jan 1989. Why?
Months are zero-based in Calendar. So 12 is interpreted as december + 1 month. Use
c.set(year, month - 1, day, 0, 0);
That's my favorite way prior to Java 8:
Date date = new GregorianCalendar(year, month - 1, day).getTime();
I'd say this is a bit cleaner than:
calendar.set(year, month - 1, day, 0, 0);
java.time
Using java.time framework built into Java 8
int year = 2015;
int month = 12;
int day = 22;
LocalDate.of(year, month, day); //2015-12-22
LocalDate.parse("2015-12-22"); //2015-12-22
//with custom formatter
DateTimeFormatter.ofPattern formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
LocalDate.parse("22-12-2015", formatter); //2015-12-22
If you need also information about time(hour,minute,second) use some conversion from LocalDate to LocalDateTime
LocalDate.parse("2015-12-22").atStartOfDay() //2015-12-22T00:00
Java's Calendar representation is not the best, they are working on it for Java 8. I would advise you to use Joda Time or another similar library.
Here is a quick example using LocalDate from the Joda Time library:
LocalDate localDate = new LocalDate(year, month, day);
Date date = localDate.toDate();
Here you can follow a quick start tutorial.
See JavaDoc:
month - the value used to set the MONTH calendar field. Month value is
0-based. e.g., 0 for January.
So, the month you set is the first month of next year.
Make your life easy when working with dates, timestamps and durations. Use HalDateTime from
http://sourceforge.net/projects/haldatetime/?source=directory
For example you can just use it to parse your input like this:
HalDateTime mydate = HalDateTime.valueOf( "25.12.1988" );
System.out.println( mydate ); // will print in ISO format: 1988-12-25
You can also specify patterns for parsing and printing.

How to identify date of 6 complete months ago

I need to identify the date which is 6 complete months ago. For example:
Feb-27, 2012(Today) - It is Feb and we don't count incomplete month, false
Feb-01, 2012 - Still Feb so don't count too, false
Jan-01, 2011 - Completed, false
Dec-01, 2011 - Completed, false
Nov-01, 2011 - Completed, false
Oct-01, 2011 - Completed, false
Sep-01, 2011 - Completed, false
Aug-01, 2011 - Completed, false
Jul-01, 2011 - Already pass 6 complete months, true
It should work in whatever date in the future.
I thought of current date minus 30*6=180 days, but it is not accurate.
It needs to be accurate because, for example, if we identify Jul 2011 is valid then we will housekeep all the data for that month.
Thanks.
I would try this simple logic to do the job.
Calendar cal = Calendar.getInstance(); //Get current date/month i.e 27 Feb, 2012
cal.add(Calendar.MONTH, -6); //Go to date, 6 months ago 27 July, 2011
cal.set(Calendar.DAY_OF_MONTH, 1); //set date, to make it 1 July, 2011
Hope this helps.
If you could use JodaTime, here is code for ±6 months calculation:
import org.joda.time.DateTime;
import org.joda.time.Months;
....
....
DateTime now = new DateTime();
DateTime then = new DateTime().withDate(2011, 8, 1);
if(Math.abs(Months.monthsBetween(now, then).getMonths()) > 6){
System.out.println("6 mo apart!");
//your logic goes here
}
Use a library like joda-time for your time and date needs. Offhand I think you could do this with:
new LocalDate().minusMonths(7).withDayOfMonth(1)
(7 months to cover any partial months... leaves an edge case of the first of the month... but eh :) )
YearMonth
The java.time.YearMonth class built into Java makes this task simple.
Get the current year-month. This requires a time zone as at any given moment the date varies around the globe by zone. On the first/last day of the month, the month can vary around the world by zone.
YearMonth ymCurrent = YearMonth.now( ZoneId.of( "America/Montreal" ) );
We know the current month is incomplete by definition. So move to the previous month.
YearMonth ymPrevious = ymCurrent.minusMonths( 1 ) ;
Move a further six months earlier if desired.
YearMonth ymSixMonthsMore = ymPrevious.minusMonths( 6 );
That YearMonth object itself may be useful in your code. You can pas these objects of this class around your code.
If you need the first day of a month, ask.
LocalDate ld = ymSixMonthsMore.atDay( 1 );
As I understand, you need to have a utility which will determine whether a variable date is 6 months before the reference date that you will set. Take a look at my code snippet for this problem. It just gets use of java.util.Calendar, you don't have to use some other libraries.
import java.util.Calendar;
public class Test
{
public static void main(String[] args)
{
Calendar cal1 = Calendar.getInstance();
cal1.set(2012, 2, 27);
Calendar cal2 = Calendar.getInstance();
cal2.set(2011, 8, 1);
boolean valid = isSixMonthsAgo(cal1, cal2);
System.out.println(valid);
}
public static boolean isSixMonthsAgo(Calendar referenceDate, Calendar dateToBeTested)
{
int year1 = referenceDate.get(Calendar.YEAR);
int month1 = referenceDate.get(Calendar.MONTH);
int year2 = dateToBeTested.get(Calendar.YEAR);
int month2 = dateToBeTested.get(Calendar.MONTH);
if ((year1 * 12 + month1) - (year2 * 12 + month2) > 6)
return true;
return false;
}
}

SimpleDateFormat Week Calculations

I'm getting some puzzling results with SimpleDateFormat and am hoping that someone can shed some light on the issue. The output:
Time = Mon Dec 27 00:00:00 PST 2010
2010-01 <--- THIS IS WHAT I DON'T UNDERSTAND
Start of week = Sun Dec 26 00:00:00 PST 2010
2010-01
End of Week = Sat Jan 01 23:59:59 PST 2011
2011-01
Should I be treating the last "week" of the year that extends to the next year as a special case? Or is this the correct way to interpret this? Obviously when attempting to organize week sequentially, the order is incorrect. Adjusting the initial values, Dec 25, 2005 is considered the 53rd week. I haven't looked at Joda yet to see if Joda produces similar results.
The relevant code:
private static Date getStartOfWeek( Date d ) {
Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.setTime( d );
calendar.set( Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek() );
return calendar.getTime();
}
private static Date getEndOfWeek( Date d ) {
Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.setTime( d );
calendar.add( Calendar.WEEK_OF_YEAR, 1 );
calendar.set( Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek() );
calendar.add( Calendar.MILLISECOND, -1 );
return calendar.getTime();
}
Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.set( 2010, Calendar.DECEMBER, 27 );
Date d = calendar.getTime();
Date start = getStartOfWeek( d );
Date end = getEndOfWeek( d );
SimpleDateFormat fmt = new SimpleDateFormat( "yyyy-ww" );
System.out.println( "Time = " + d );
System.out.println( fmt.format( d ) );
System.out.println( "Start of week = " + start );
System.out.println( fmt.format( start ) );
System.out.println( "End of Week = " + end );
System.out.println( fmt.format( end ) );
Background: I found this when using the crosstab (date grouped into week) in JasperReports.
EDIT: I am using JDK 1.6.0_25
EDIT: It seems that I will have to use Joda to get the correct result. TO get the week start/end, I ended up using: LocalDate.withDayOfWeek. To retrieve the year and week number, I used DateTime.getWeekyear and DateTime.getWeekOfWeekyear.
The bug is in your formatting code, not Java.
The surprising behavior is due to an esoteric rule in date notation. Note that ISO 8601 (rather confusingly) specifies different rules for year boundaries when using week numbers. In particular, 2010-12-27 is considered part of 2011 when using week numbers.
As a result, you should be using the "week year" YYYY rather than the usual year yyyy. (See http://download.oracle.com/javase/7/docs/api/java/util/GregorianCalendar.html#week_year and the last example in http://download.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html.)
Also, the standard notation for dates uses an explicit 'W', so you should use new SimpleDateFormat( "YYYY-'W'ww" ) instead.
Edit: There's another problem. Java seems to default to the non-standard calendar.getMinimalDaysInFirstWeek() == 1, so you have to set
calendar.setMinimalDaysInFirstWeek( 4 );
in order to get the correct year.
Edit: From reading the Calendar javadocs, you might also need to set the starting day to Monday. Further, the YYYY format specifier seems to be new in Java 1.7. In light of this, unless you're willing to upgrade to a pre-release Java version, I recommend just using Joda Time.
From ISO Week
The first week of a year is the week that contains the first Thursday
of the year.
So the behavior has nothing to do with Java or Joda. This is how the "week of the year" is implemented worldwide (if they follow the ISO standard)
the standadr java Date & Time classes are not well designed and sometimes don't work as expected. use instead Joda Time
Yes, this looks to be a bug in Java, and not in the formatting code. If you print:
System.out.println("Week = " + calendar.get(Calendar.WEEK_OF_YEAR));
It also shows 1.
If you change your date to something not so close to the end of the year, eg:
calendar.set(2010, Calendar.NOVEMBER, 27);
Then the output looks right. BTW, I tested using Sun 1.6.0_25 64bit VM.

Java DateFormat and SimpleDateFormat returning a date that is incorrect

Today is Tuesday, February 9, 2010 and when I print the date I get the wrong date:
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
Date today = formatter.parse(String.format("%04d-%02d-%02d",
Calendar.getInstance().get(Calendar.YEAR),
Calendar.getInstance().get(Calendar.MONTH),
Calendar.getInstance().get(Calendar.DAY_OF_MONTH)));
System.out.println("Today is " + today.toString());
The print line results in: "Today is Sat Jan 09 00:00:00 CST 2010"
It most certainly is not Saturday Jan 09, it's Tuesday Feb 09. I'm assuming I'm doing something wrong, so can anybody let me know what's wrong here? Do I have to manually set the day of week?
Update
Note: I don't want to initialize today with new Date() because I want the hours, minutes, seconds and milliseconds initialized to 0. This is necessary so I can compare a user input date with today: if the user inputs today's date and I use the formatter to construct a Date object, then if I initialize today with new Date() and I compare the two dates- today will be after the user selected date (which is incorrect). Thus I need to initialize today at the beginning of the day without the hr/min/sec/ms.
Confusingly, Calendar months count from 0 (January) to 11 (December), so you're passing "2010-01-09" to formatter.parse() when you extract the MONTH field from the Calendar.
There's a discussion of this in a related SO question.
If you don't want to use JodaTime you could use:
Calendar calendar = Calendar.getInstance();
calendar.set( Calendar.HOUR_OF_DAY, 0 );
calendar.set( Calendar.MINUTE, 0 );
calendar.set( Calendar.SECOND, 0 );
calendar.set( Calendar.MILLISECOND, 0 );
Date today = calendar.getTime();
This is much more efficient and less error-prone than your String formatting/parsing approach.
If you can use JodaTime this is a much preferred method:
LocalDate date = new DateTime().toLocaleDate();

Categories

Resources