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
Related
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 );
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.
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.
In Joda-Time, is there a way to get the date of the first day of the week(monday).
for instance i want to find out what date was this weeks monday based on todays current date 21/01/11
Cheers in advance.
edit: i also wish to find the date for the end of the week i.e sunday's date. cheers
Try LocalDate.withDayOfWeek:
LocalDate now = new LocalDate();
System.out.println(now.withDayOfWeek(DateTimeConstants.MONDAY)); //prints 2011-01-17
System.out.println(now.withDayOfWeek(DateTimeConstants.SUNDAY)); //prints 2011-01-23
LocalDate today = new LocalDate();
LocalDate weekStart = today.dayOfWeek().withMinimumValue();
LocalDate weekEnd = today.dayOfWeek().withMaximumValue();
Will give you the first and last days i.e Monday and sunday
Another option is to use roundFloorCopy. This looks like the following:
LocalDate startOfWeek = new LocalDate().weekOfWeekyear().roundFloorCopy();
For the last day of the standard week (Sunday) use roundCeilingCopy and minusDays…
LocalDate lastDateOfWeek = new LocalDate().weekOfWeekyear().roundCeilingCopy().minusDays( 1 );
Also works for DateTime. And works for end of week (exclusive).
DateTime dateTime = new DateTime();
DateTime startOfWeek = dateTime.weekOfWeekyear().roundFloorCopy();
DateTime endOfWeek = dateTime.weekOfWeekyear().roundCeilingCopy();
Dump to console…
System.out.println( "dateTime " + dateTime );
System.out.println( "startOfWeek " + startOfWeek );
System.out.println( "endOfWeek " + endOfWeek );
When run…
dateTime 2014-01-24T00:00:34.955-08:00
startOfWeek 2014-01-20T00:00:00.000-08:00
endOfWeek 2014-01-27T00:00:00.000-08:00
You can use the getDayOfWeek() method that gives you back 1 for Monday, 2 for Tue, .., 7 for Sunday in order to go back that many days and reach Monday:
import org.joda.time.DateTime;
public class JodaTest {
public static void main(String[] args) {
DateTime date = new DateTime();
System.out.println(date);
//2011-01-21T15:06:18.713Z
System.out.println(date.minusDays(date.getDayOfWeek()-1));
//2011-01-17T15:06:18.713Z
}
}
See the section "Querying DateTimes" of the Joda-Time user guide.
Here is the general algorithm I would follow:
find the day-of-week of the target date (Jan 21 2011 as you mentioned)
determine how many days ahead of Monday this is
Subtract the value of #2 from the target date using dateTime.minusDays(n)
This question already has answers here:
Is there a good way to get the date of the coming Wednesday?
(6 answers)
Closed 3 years ago.
I asked How to detect if a date is within this or next week in Java? but the answers were confusing, so now I think if I can find the past Sunday and the coming Sunday, any day in between is this week, and any day between the coming Sunday and the Sunday after that is next week, am I correct ?
So my new question is : How to get the past Sunday and the coming Sunday in Java ?
java.time
Briefly:
LocalDate.now().with( next( SUNDAY ) )
See this code run live at IdeOne.com.
Details
I thought I'd add a Java 8 solution for posterity. Using LocalDate, DayOfWeek, and TemporalAdjuster implementation found in the TemporalAdjusters class.
final LocalDate today = LocalDate.of(2015, 11, 20);
final LocalDate nextSunday = today.with(next(SUNDAY));
final LocalDate thisPastSunday = today.with(previous(SUNDAY));
This approach also works for other temporal classes like ZonedDateTime.
import
As written, it assumes the following static imports:
import java.time.LocalDate;
import static java.time.DayOfWeek.SUNDAY;
import static java.time.temporal.TemporalAdjusters.next;
import static java.time.temporal.TemporalAdjusters.previous;
How about this :
Calendar c=Calendar.getInstance();
c.set(Calendar.DAY_OF_WEEK,Calendar.SUNDAY);
c.set(Calendar.HOUR_OF_DAY,0);
c.set(Calendar.MINUTE,0);
c.set(Calendar.SECOND,0);
DateFormat df=new SimpleDateFormat("EEE yyyy/MM/dd HH:mm:ss");
System.out.println(df.format(c.getTime())); // This past Sunday [ May include today ]
c.add(Calendar.DATE,7);
System.out.println(df.format(c.getTime())); // Next Sunday
c.add(Calendar.DATE,7);
System.out.println(df.format(c.getTime())); // Sunday after next
The result :
Sun 2010/12/26 00:00:00
Sun 2011/01/02 00:00:00
Sun 2011/01/09 00:00:00
Any day between the first two is this week, anything between the last two is next week.
Without using a better time/date package...
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL);
Calendar now = new GregorianCalendar();
Calendar start = new GregorianCalendar(now.get(Calendar.YEAR),
now.get(Calendar.MONTH), now.get(Calendar.DAY_OF_MONTH) );
while (start.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY) {
start.add(Calendar.DAY_OF_WEEK, -1);
}
Calendar end = (Calendar) start.clone();
end.add(Calendar.DAY_OF_MONTH, 7);
System.out.println(df.format(now.getTime()) );
System.out.println(df.format(start.getTime()) );
System.out.println(df.format(end.getTime()) );
If today is Sunday, it is considered the start of the time period. If you want a period of this week and next week (as it sounds from your question), you can substitute 14 instead of 7 in the end.add(...) line. The times are set to midnight for comparison of another object falling between start and end.
First, don't use the Date/Time package from Java. There is a much better utility package called Joda-Time - download that and use it.
To determine if your time is in this week, last week, or any week at all, do this:
Create two Interval objects - one for last week and one for this week
Use the contains( long ) method to determine which interval holds the date you are looking for.
There are several cool ways you can create two back to back weeks. You could set up a Duration of one week, find the start time for the first week, and just create two Intervals based on that start time. Feel free to find any other way that works for you - the package has numerous ways to get to what you want.
EDIT:
Joda-Time can be downloaded here, and here is an example of how Joda would do this:
// Get the date today, and then select midnight of the first day of the week
// Joda uses ISO weeks, so all weeks start on Monday.
// If you want to change the time zone, pass a DateTimeZone to the method toDateTimeAtStartOfDay()
DateTime midnightToday = new LocalDate().toDateTimeAtStartOfDay();
DateTime midnightMonday = midnightToday.withDayOfWeek( DateTimeConstants.MONDAY );
// If your week starts on Sunday, you need to subtract one. Adjust accordingly.
DateTime midnightSunday = midnightMonday.plusDays( -1 );
DateTime midnightNextSunday = midnightSunday.plusDays( 7 );
DateTime midnightSundayAfter = midnightNextSunday.plusDays( 7 );
Interval thisWeek = new Interval( midnightSunday, midnightNextSunday );
Interval nextWeek = new Interval( midnightNextSunday, midnightSundayAfter );
if ( thisWeek.contains( someDate.getTime() )) System.out.println("This week");
if ( nextWeek.contains( someDate.getTime() )) System.out.println("Next week");
Given bellow next Sunday code and you can easily figure out how to find past Sunday.
private static void nextSunday() throws ParseException
{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
int weekday = calendar.get(Calendar.DAY_OF_WEEK);
int days = Calendar.SUNDAY - weekday;
if (days < 0)
{
days += 7;
}
calendar.add(Calendar.DAY_OF_YEAR, days);
System.out.println(sdf.format(calendar.getTime()));
}
I recently developed Lamma Date which is designed to solve this use case:
Date today = new Date(2014, 7, 1); // assume today is 2014-07-01
Date previousSunday = today.previousOrSame(DayOfWeek.SUNDAY); // 2014-06-29
Date nextSunday = today.next(DayOfWeek.SUNDAY); // 2014-07-06
http://download.oracle.com/javase/1.4.2/docs/api/java/util/Date.html
I recommend Calendar.get(Calendar.DAY_OF_WEEK)
You could try to work with the Calendar.WEEK_OF_YEAR field, which gives you the numeric representation of the week within the current year.
#Test
public void testThisAndNextWeek() throws Exception {
GregorianCalendar lastWeekCal = new GregorianCalendar(2010,
Calendar.DECEMBER, 26);
int lastWeek = lastWeekCal.get(Calendar.WEEK_OF_YEAR);
GregorianCalendar nextWeekCal = new GregorianCalendar(2011,
Calendar.JANUARY, 4);
int nextWeek = nextWeekCal.get(Calendar.WEEK_OF_YEAR);
GregorianCalendar todayCal = new GregorianCalendar(2010,
Calendar.DECEMBER, 27);
int currentWeek = todayCal.get(Calendar.WEEK_OF_YEAR);
assertTrue(lastWeekCal.before(todayCal));
assertTrue(nextWeekCal.after(todayCal));
assertEquals(51, lastWeek);
assertEquals(52, currentWeek);
// New Year.. so it's 1
assertEquals(1, nextWeek);
}
My Solution:
LocalDate date = ...;
LocalDate newWeekDate = date.plusDays(1);
while (newWeekDate.getDayOfWeek() != DayOfWeek.SATURDAY &&
newWeekDate.getDayOfWeek() != DayOfWeek.SUNDAY) {
newWeekDate = date.plusDays(1);
}