Calendar add method not working as expected - java

I want set a (Gregorian) Calendar time to start-of-day April 1, 2016. I do this by setting month, day and year, and then setting all the time fields to their minimum values, giving me:
04/01/2016 12:00:00:000
If I subtract one millisecond I expect to get the last millisecond on the previous day, but instead I get the last millisecond on the same day:
04/01/2016 11:59:59:999
(Note: I get similar results if I subtract one second, minute or hour.)
What am I missing? Sample code follows, thanks.
package com.scg.domain;
import java.text.SimpleDateFormat;
import java.util.Calendar;
public class AdHoc
{
private static final int[] UNUSED_CAL_FIELDS =
{
Calendar.HOUR,
Calendar.MINUTE,
Calendar.SECOND,
Calendar.MILLISECOND
};
public static void main(String[] args)
{
Calendar cal = getGoodDate( Calendar.APRIL, 1,2016 );
System.out.println( cal.getCalendarType() );
adjustTime( "present", cal, 0 );
adjustTime( "past", cal, -1 );
adjustTime( "future", cal, 1 );
}
private static void adjustTime( String comment, Calendar cal, int incr )
{
Calendar newCal = Calendar.getInstance();
newCal.setTime( cal.getTime() );
newCal.add( Calendar.MILLISECOND, incr );
SimpleDateFormat fmt =
new SimpleDateFormat( "MM/dd/YYYY HH:mm:ss:SSS" );
System.out.println( comment + ": " + fmt.format( newCal.getTime() ) );
}
private static Calendar getGoodDate( int month, int day, int year )
{
Calendar cal = Calendar.getInstance();
cal.set( Calendar.YEAR, year );
cal.set( Calendar.MONTH, month );
cal.set( Calendar.DAY_OF_MONTH, day );
for ( int field : UNUSED_CAL_FIELDS )
cal.set( field, cal.getMinimum( field ) );
return cal;
}
}

You've used Calendar.HOUR, which controls only the 1-12 hour, not the 0-23 hour. Because of this, even though getMinimum returns 0, it's interpreted as 12:00 in whichever of AM or PM cal already is in, which must be PM from getInstance() (returns "now"). You really have 12:00 noon (PM). When you subtract a millisecond, it's still the same day.
To set it to midnight, try Calendar.HOUR_OF_DAY, which controls the 0-23 hour.
With this change, I get the output:
gregory
present: 04/01/2016 00:00:00:000
past: 03/31/2016 23:59:59:999
future: 04/01/2016 00:00:00:001

Related

find out the date from an input string

I am trying to find out the specific date from a given input string, which can be like "201411W3". I know that the week is 3rd from this string(W3) and the event will be on Friday, so I want to find the date of the 3rd Friday. I did something like this:
public static Date getLastFriday( int month, int year ) {
Calendar cal = Calendar.getInstance();
cal.set( year, month, 1 );
cal.add( Calendar.DAY_OF_MONTH, - ( cal.get( Calendar.DAY_OF_WEEK ) % 7 + 8 ) );
return cal.getTime();
}
when I call this method: getLastFriday(11, 2014), I get the value "Fri Nov 21 13:16:57 EST 2014" which I need to parse to find out the date. is there any way to get just the date from the result?
Thanks!
If I understood you, then you can use below code as reference -
import java.text.SimpleDateFormat;
import java.util.Calendar;
public class Test{
public static void main (String[] args)
{
String str="201411W3";
String[] strSplitted = str.split("W");
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.MONTH, Integer.parseInt(strSplitted[0].substring(4,6))-1);
calendar.set(Calendar.YEAR, Integer.parseInt(strSplitted[0].substring(0,4)));
calendar.set(Calendar.DAY_OF_MONTH, 1);
if(calendar.get(Calendar.DAY_OF_WEEK)==7)
{
calendar.set(Calendar.WEEK_OF_MONTH, Integer.parseInt(strSplitted[1])+1);
}
else
{
calendar.set(Calendar.WEEK_OF_MONTH, Integer.parseInt(strSplitted[1]));
}
calendar.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
String formattedDate = new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime());
System.out.println(formattedDate);
}
}
Output : 2014-11-21 You can change the format to any format you want.
If you just want to get the month and day without the seconds, you could call .get(Calendar.MONTH) and .get(Calendar.DATE) and pass them into the constructor of a new date object and return that object.
More info: here
Use this SimpleDateFormat
I didn't test the following code but it will work like:
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy");
Date myDate = sdf.parse("Fri Nov 21 13:16:57 EST 2014");

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

The constructor Time is deprecated

private static final Time BEGIN = new Time(9, 0, 0);
private static final Time END = new Time(20, 0, 0);
The constructor Time is deprecated, is there a way to fix these declarations?
You can now use as mentioned by javadocs.
Time(long time)
Constructs a Time object using a milliseconds time value.
Short search gave me this :
Calendar cal = Calendar.getInstance();
// set Date portion to January 1, 1970
cal.set( cal.YEAR, 1970 );
cal.set( cal.MONTH, cal.JANUARY );
cal.set( cal.DATE, 1 );
cal.set( cal.MILLISECOND, 0 );
java.sql.Time jsqlT =
new java.sql.Time( cal.getTime().getTime() );

Calendar add behaviour

Want to get first day of the next week (next monday), but call to getTime() changes the Calendar object.
Please tell me the right way to get first day of the next week.
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
public class Main {
public static void main(String[] args) {
{
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
final Calendar cal = new GregorianCalendar( 2013, 5, 6 );
cal.setFirstDayOfWeek( Calendar.MONDAY );
//System.out.println( sdf.format( cal.getTime() ) );
cal.set( Calendar.DAY_OF_WEEK, Calendar.MONDAY );
System.out.println( sdf.format( cal.getTime() ) ); // 2013-06-06
cal.add( Calendar.WEEK_OF_YEAR, 1 );
System.out.println( sdf.format( cal.getTime() ) ); // 2013-06-13
}
{
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
final Calendar cal = new GregorianCalendar( 2013, 5, 6 );
cal.setFirstDayOfWeek( Calendar.MONDAY );
System.out.println( sdf.format( cal.getTime() ) ); // 2013-06-06
cal.set( Calendar.DAY_OF_WEEK, Calendar.MONDAY );
System.out.println( sdf.format( cal.getTime() ) ); // 2013-06-03
cal.add( Calendar.WEEK_OF_YEAR, 1 );
System.out.println( sdf.format( cal.getTime() ) ); // 2013-06-10
}
}
}
This is a nice example...
The Calendar is not easy to handle. You problem is the evaluation of the date.
The date of the Calendar is newly evaluated if you call e.g. getTime() or add().
In the second (correct) example you call getTime() after setting the first day of the week and the calendar is set to 2013-06-06. After that you change the day of the week and set the calendar new (via getTime()). Therefore it is now set to Monday.
In the first example you set the Calendar to the date and set the day of week. This leads to an invalid date (temporarily). 2013-06-06 is a Thursday and you set Monday. Now which one is the correct day of week? The Calendar implementation now chooses Thursday.
This is also well documented in the Javadoc. The section is named Calendar Fields Resolution.

How can I know all the tuesdays of a given month?

For instance in Sept I would need:
1,8,15,22 and 29
Thanks
Look up the Doomsday Rule - you should be able to apply that algorithm to your problem.
The simplest (naive) solution I can see is:
Get a Calendar (Calendar.getInstance())
Set the year, month, date etc (zero out other fields).
Then iterate adding one to the date (stop if you're not in the correct month - calendar.get(Calendar.MONTH))
while iterating, if calendar.get(Calendar.DAY_OF_WEEK) == Calendar.TUESDAY then increment the Tuesday counter.
As per daveb answer I've got:
import java.util.Calendar;
import static java.util.Calendar.*;
public class DiasDelMes {
public static void main( String [] args ) {
Calendar calendar = getInstance();
calendar.set( DAY_OF_MONTH, 1 );
int month = calendar.get( MONTH );
while( calendar.get( MONTH ) == month ) {
if( calendar.get( DAY_OF_WEEK ) == TUESDAY ) {
System.out.println( calendar.get( DAY_OF_MONTH ) ) ;
}
calendar.add( DAY_OF_MONTH , 1 );
}
}
}
I was looking for the answer for such question but to solve it in Java 8.
Here is my solution:
public Stream<Temporal> listAllDaysInMonthIterative(Month month, DayOfWeek dow) {
List<Temporal> dates = new ArrayList<>();
LocalDate date = LocalDate.of(Year.now().getValue(), month.getValue(), 1);
TemporalAdjuster adjuster = TemporalAdjusters.nextOrSame(dow);
while (date.with(adjuster).get(ChronoField.MONTH_OF_YEAR) == month.getValue()) {
date = date.with(adjuster);
dates.add(date);
adjuster = TemporalAdjusters.next(dow);
}
return dates.stream();
}
Run:
#Test
public void testMondaysInMonth() {
MonthLengthReporter reporter = new MonthLengthReporter();
Stream days = reporter.listAllDaysInMonthIterative(Month.MARCH, DayOfWeek.MONDAY);
days.forEach(System.out::println);
}

Categories

Resources