Get Previous Day [duplicate] - java

This question already has answers here:
Closed 13 years ago.
Possible Duplicate:
How to determine the date one day prior to a given date in Java?
If I have a Java.Util.Date object, what is the best way to get an object representing the 24 hours in the past of it?

Using Java 1.6 java.util.Calendar.add:
public static Date subtractDay(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(Calendar.DAY_OF_MONTH, -1);
return cal.getTime();
}
Others suggest using Joda Time, which is currently JSR 310, and should later be included in Java itself.

The important thing to remember is that the Date class should represent any points in time whilst the Calendar class is used to manipulate those points in time. Last of all, SimpleDateFormat will represent them as Strings.
So, the best way is to use the Calendar class to calculate the new Date for you. This will ensure that any vagaries (Daylight Saving, Leap Years and the like) are accounted for.
I'm assuming that you don't really want to find '24 Hours previous' but actually do want a new Date instance representing 'this time yesterday' - either way, you can ask the Calendar instance for a Date 24Hours prior to another or 1 Day prior.
The Daylight savings is a great example. The UK 'sprang forward' on the 26th March 2009. So, 1 day prior to 3.00a.m. on the 26.Mar.2009 should yield 3.00a.m. 25.Mar.2009 but 24 Hrs prior will yield 2.00a.m.
public class DateTests extends TestCase {
private static String EXPECTED_SUMMER_TIME = "2009.Mar.29 03:00:00";
private static String EXPECTED_SUMMER_TIME_LESS_DAY = "2009.Mar.28 03:00:00";
private static String EXPECTED_SUMMER_TIME_LESS_24_HRS = "2009.Mar.28 02:00:00";
private static String EXPECTED_SUMMER_TIME_LESS_FURTHER_24_HRS = "2009.Mar.27 02:00:00";
public void testSubtractDayOr24Hours() {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MMM.dd HH:mm:SS");
Calendar calendar = Calendar.getInstance();
// Create our reference date, 3.00 a.m. on the day the clocks go forward (they 'went' forward at 02.00)
calendar.clear();
calendar.set(2009, 2, 29, 3, 0);
Date summerTime = calendar.getTime(); // Sun Mar 29 03:00:00 BST 2009
String formattedSummerTime = formatter.format(summerTime);
calendar.add(Calendar.DAY_OF_MONTH, -1);
// Our reference date less 'a day'
Date summerTimeLessADay = calendar.getTime(); // Sat Mar 28 03:00:00 GMT 2009
String formattedSummerTimeLessADay = formatter.format(summerTimeLessADay);
// reset the calendar instance to the reference day
calendar.setTime(summerTime);
// Our reference date less '24 hours' (is not quite 24 hours)
calendar.add(Calendar.HOUR, -24);
Date summerTimeLess24Hrs = calendar.getTime(); // Sat Mar 28 02:00:00 GMT 2009
String formattedSummerTimeLess24Hrs = formatter.format(summerTimeLess24Hrs);
// Third date shows that taking a further 24 hours from yields expected result
calendar.add(Calendar.HOUR, -24);
Date summerTimeLessFurther24Hrs = calendar.getTime(); // Fri Mar 27 02:00:00 GMT 2009
String formattedSummerTimeLessFurther24Hrs = formatter.format(summerTimeLessFurther24Hrs);
// reset the calendar once more to the day before
calendar.setTime(summerTimeLess24Hrs);
// Take a 'day' from the Sat will yield the same result as date 03 because Daylight Saving is not a factor
calendar.add(Calendar.DAY_OF_MONTH, -1);
Date summerTimeLessFurtherDay = calendar.getTime(); // Fri Mar 27 02:00:00 GMT 2009
String formattedSummerTimeLessFurtherDay = formatter.format(summerTimeLessFurtherDay);
assert(formattedSummerTime.equals(EXPECTED_SUMMER_TIME));
assert(formattedSummerTimeLessADay.equals(EXPECTED_SUMMER_TIME_LESS_DAY));
assert(formattedSummerTimeLess24Hrs.equals(EXPECTED_SUMMER_TIME_LESS_24_HRS));
assert(formattedSummerTimeLessFurther24Hrs.equals(EXPECTED_SUMMER_TIME_LESS_FURTHER_24_HRS));
// This last test proves that taking 24 hors vs. A Day usually yields the same result
assert(formattedSummerTimeLessFurther24Hrs.equals(formattedSummerTimeLessFurtherDay));
}
}
For testing date functions, wwwdot-timeanddate-dot-com is a great resource.

subtract 1000*60*60*24 from the time and create a new date.
Date yesterday = new Date(d.getTime() - (1000*60*60*24));

int dayInMs = 1000 * 60 * 60 * 24;
Date previousDay = new Date(olddate.getTime() - dayInMs);
Personally if there are a lot of time/date calculations, I'd go with Joda-time.

Related

How to calculate next week?

I want to precisely calculate the time one week from a given date, but the output I get back is one hour early.
code:
long DURATION = 7 * 24 * 60 * 60 * 1000;
System.out.println(" now: " + new Date(System.currentTimeMillis()));
System.out.println("next week: " + new Date(System.currentTimeMillis() + DURATION));
output:
now: Wed Sep 16 09:52:36 IRDT 2015
next week: Wed Sep 23 08:52:36 IRST 2015
How can I calculate this correctly?
Never, ever rely on millisecond arithmetic, there are too many rules and gotchas to make it of any worth (even over a small span of time), instead use a dedicated library, like Java 8's Time API, JodaTime or even Calendar
Java 8
LocalDateTime now = LocalDateTime.now();
LocalDateTime then = now.plusDays(7);
System.out.println(now);
System.out.println(then);
Which outputs
2015-09-16T15:34:14.771
2015-09-23T15:34:14.771
JodaTime
LocalDateTime now = LocalDateTime.now();
LocalDateTime then = now.plusDays(7);
System.out.println(now);
System.out.println(then);
Which outputs
2015-09-16T15:35:19.954
2015-09-23T15:35:19.954
Calendar
When you can't use Java 8 or JodaTime
Calendar cal = Calendar.getInstance();
Date now = cal.getTime();
cal.add(Calendar.DATE, 7);
Date then = cal.getTime();
System.out.println(now);
System.out.println(then);
Which outputs
Wed Sep 16 15:36:39 EST 2015
Wed Sep 23 15:36:39 EST 2015
nb: The "problem" you seem to be having, isn't a problem at all, but simply the fact that over the period, your time zone seems to have entered/exited day light savings, so Date is displaying the time, with it's correct offset
Try this
Calendar cal = Calendar.getInstance();
System.out.println(cal.getTime());
cal.add(Calendar.DAY_OF_MONTH, 7);
System.out.println(cal.getTime());
The difference is because of the different timezone. IRDT is +0430 and IRST is +0330
To overcome this issue you can use the JodaTime.
LocalDateTime now = LocalDateTime.now();
LocalDateTime nextweek = now.plusDays(7);
System.out.println(now);
System.out.println(nextweek);
As other said. It would be better to use Calendar or JodaTime library. But the question is why you were not getting the desired result. It was because currentTimeMillis() calculates time between "computer time" and coordinated universal time (UTC). Now consider following case.
long DURATION = 7 * 24 * 60 * 60 * 1000;
Date now = new Date();
Date nextWeek = new Date(now.getTime() + DURATION);
System.out.println(" now: " + now);
System.out.println("next week: " + nextWeek);
here Date.getTime() calculate time from 00:00:00 GMT every time and then when converted to string will give time for your local time zone.
Edit :
I was wrong. The reason is as simon said.
The actual "why" is that IRDT (Iran Daylight Time) ends on September
22nd. That's why the first date (September 16th) in the OP's post is
displayed as IRDT and the second date (September 23rd) is displayed as
IRST. Because IRST (Iran Standard Time) is one hour earlier than IRDT
the time displayed is 08:52:36 instead of 09:52:36.

Good way to convert integer YYYYMMDD into java.util.Date with local time zone

I understand this question could look like FAQ subject but critical things here is time zone and performance. I have integer YYYYMMDD date (20150131 is example). Here is good 'almost working' solution:
import org.joda.time.DateTime;
import java.util.Date;
// ...
public Date extract(final int intDate) {
Date result = null;
try {
result = new DateTime(
intDate / 10000,
(intDate / 100) % 100,
intDate % 100,
0,
0,
0,
0).toDate();
} catch (final IllegalArgumentException e) {
// Log failure
}
return result;
}
'almost' is because having 0x0126810d and EET (UTC+2 / +3 when DST) time zone I receive:
java.lang.IllegalArgumentException: Illegal instant due to time zone
offset transition: 1930-06-20T22:00:00.000
At least using JODA 1.6. I cannot switch easily.
But I'd like it to be 1930-06-21T00:00:00.000+02:00 and I don't care about UTC representation.
Is it possible at all (can java.util.date store such date)?
OK, any better high performance way to achieve this (JODA is just remedy here, not critical)?
Yes, I understand this time does not exist:
roman#node4:$ zdump -v Europe/Kiev | grep 1930
Europe/Kiev Fri Jun 20 21:59:59 1930 UTC = Fri Jun 20 23:59:59 1930 EET isdst=0 gmtoff=7200
Europe/Kiev Fri Jun 20 22:00:00 1930 UTC = Sat Jun 21 01:00:00 1930 MSK isdst=0 gmtoff=10800
java.time and LocalDate
No matter if using Joda-Time (as in your question) or java.time, the modern Java date and time API, I believe that the solution to your problem is using LocalDate. I suggest that you simply stick to this and neither use org.joda.time.DateTime nor java.util.Date. In particular not the latter, it was always poorly designed and is now long outdated.
I am presenting to ways.
int intDate = 19300621; // 0x0126810d
String asString = String.valueOf(intDate);
LocalDate date = LocalDate.parse(asString, DateTimeFormatter.BASIC_ISO_DATE);
System.out.println(date);
1930-06-21
I find this code clearer to read than the code doing divisions and modulo operations. It’s not as efficient, but for more than 19 out of 20 cases this should be no concern. If you like the divisions, you can of course do them with java.time too:
int year = intDate / 10000;
int monthDay = intDate % 10000;
int month = monthDay / 100;
int day = monthDay % 100;
LocalDate date = LocalDate.of(year, month, day);
If you do need a java.util.Date for a legacy API not yet upgraded to java. time (or Joda-Time), convert like this (no matter which of the above conversions you used):
Instant asInstant = date.atStartOfDay(ZoneId.systemDefault()).toInstant();
Date oldfashionedDate = Date.from(asInstant);
System.out.println(oldfashionedDate);
Output when my default time zone is set to Europe/Zaporozhye:
Sat Jun 21 01:00:00 EET 1930
(We notice that we get 01:00:00 because of transition to summer time (DST). The time of 00:00:00 didn’t exist on this day in this time zone.)
If still using Joda-Time
If you are still using Joda-Time, your own answer using toDateTimeAtStartOfDay() is just fine.
PS I reproduced your problem with Joda-Time 2.9.9, my time zone set to Europe/Zaporozhye and your integer of 19300621 (don’t know why you gave it as hex, 0x0126810d). I got an exception similar to yours: org.joda.time.IllegalInstantException: Illegal instant due to time zone offset transition (daylight savings time 'gap'): 1930-06-21T00:00:00.000 (Europe/Zaporozhye).
Link
Oracle tutorial: Date Time explaining how to use java.time.
I suggest the following:
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month);
cal.set(Calendar.DAY_OF_MONTH, dayOfMonth);
result = cal.getTime();
OK, finally got the following fragment and it works most close to my expectations. Like SDF but many times faster - like no string parsing just to get digits:
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
public static Date toDateJoda(int intDate) {
LocalDate ldt = new LocalDate(
intDate / 10000,
(intDate / 100) % 100,
intDate % 100);
DateTime dt = ldt.toDateTimeAtStartOfDay();
return dt.toDate();
}
Parses everything and gets next valid date / time for cases like mine.
OK, I think I managed to replicate your problem, by doing:
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Kiev"));
System.out.println( extract(0x0126810d));
(Previously I tried that with "EET", but apparently that gets a different time zone altogether)
I get an illegal argument exception, though the date it mentions is a bit different. This could be because of my version of Joda.
Illegal instant due to time zone offset transition (daylight savings time 'gap'): 1930-06-21T00:00:00.000 (Europe/Kiev)
Well, the way to solve it is not to be in the Europe/Kiev zone, at least for the sake of the Joda conversion:
public static Date extract(final int intDate) {
Date result = null;
DateTimeZone tz = DateTimeZone.forOffsetHours(2);
try {
result = new DateTime(
intDate / 10000,
(intDate / 100) % 100,
intDate % 100,
0,
0,
0,
0,
tz).toDate();
} catch (final IllegalArgumentException e) {
System.err.println(e.getMessage());
return null;
}
return result;
}
This would avoid the error. You could move the tz variable definition and initialization to a field if you wish to improve performance in case you are calling the extract method a lot of times.
Mind you that when you print the resulting Date object using the default date format, which in turn uses the default time zone (Europe/Kiev), the result would be:
Sat Jun 21 01:00:00 EET 1930
You can print it properly with:
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
fmt.setTimeZone(TimeZone.getTimeZone("GMT+2"));
System.out.println(fmt.format( extract(0x0126810d)));
But maybe if you don't want to take DST into consideration, you should just work with the dates as if they were UTC. It depends what you want to do with them, really.
One last note: it's really easy to achieve the same result with Calendar:
public static Date extract2(final int intDate) {
cal.set(intDate / 10000, ( intDate / 100 ) % 100 - 1, intDate % 100);
return cal.getTime();
}
Where cal is a Calendar instance set in a field to avoid repeatedly creating and clearing it:
public static final Calendar cal;
static {
cal = Calendar.getInstance();
cal.clear();
}
(Mind multithreading, though).
Not sure about the performance problems you mentioned, and how critical the difference is.

Timestamp to Date issue

I'm trying to create a function that convert a timestamp to Date object.
My problem is that using this online tools i reach correctly to convert timestamp to date but using java it doesn't convert correctly.
This is what i try:
public static Date getDateFromUUID(UUID uuid) {
Calendar uuidEpoch = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
uuidEpoch.clear();
uuidEpoch.set(1582, 9, 15, 0, 0, 0);
long epochMillis = uuidEpoch.getTime().getTime();
long time = (uuid.timestamp() / 10000L) + epochMillis;
Calendar start = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
Calendar end = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
start.setTimeInMillis(time*1000);
end.set(start.get(Calendar.YEAR), start.get(Calendar.MONTH), start.get(Calendar.DAY_OF_MONTH),0,0,0);
return end.getTime();
}
I'm trying using that uuid: a261ae00-2a9c-11b2-ae56-bcee7be23398
it correctly converts to timestamp : 1406412000
Using this:
Calendar start = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
Calendar end = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
start.setTimeInMillis(time*1000);
end.set(start.get(Calendar.YEAR), start.get(Calendar.MONTH), start.get(Calendar.DAY_OF_MONTH),0,0,0);
return end.getTime();
I need to remove hours, minutes and seconds and take only years,months and days.
but it convert timestamp to
Sat Jul 26 02:00:00 CEST 2014
Instead of
Sun Jul 27 00:00:00 CEST 2014
what could be my mistake?
Thanks!
Your time zone if wrong. Notice that output is CEST but you set the calendar to UTC. The delta between these two is 2 hours. When you output the Date you need to set the timezone appropriately.

Date difference calculation error

The following code does not appear to calculate the correct value for spanNow. Having just run the code today spanYear is correct at 31535999 but for spanNow I have a value 23363788 which appears wrong. The string representation s correctly contains Tue Oct 29 09:56:28 GMT 2013. However 23363788 / 3600 / 24 to get day of year gives 270. The 270's day of the year is Sept 27th, not 29th October. Why the discrepancy and what is the correct way to accurately calculate the number of seconds between two dates?
Thanks Mark
Calendar c = Calendar.getInstance();
int year=c.get(Calendar.YEAR);
GregorianCalendar g = new GregorianCalendar(year,1,1,0,0,0);
Date start = g.getTime();
g = new GregorianCalendar(year,12,31,23,59,59);
Date end = g.getTime();
long spanYear = TimeUnit.MILLISECONDS.toSeconds(end.getTime()-start.getTime());
Date now = new Date();
String s = now.toString();
long spanNow = TimeUnit.MILLISECONDS.toSeconds(now.getTime()-start.getTime());
From the documentation:
month - the value used to set the MONTH calendar field in the calendar. Month value is 0-based. e.g., 0 for January.
so use
GregorianCalendar g = new GregorianCalendar(year,0,1,0,0,0);

java.util.Calendar confusion

I have a problem using java.util.Calendar and commons-lang DateUtil
The problem is that my test works correctly on local machine and fails on CloudBees. Seems like there are problems with locales, but I'm not sure.
Here is the code:
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
//bla-bla-bla
public static final String TEST_DATE_AS_STRING = "13 10 2012 20:50:44";
public static final int MILLIS_IN_HOUR = 3600000;
private static final String LEAP_WEEK_DATE_AS_STRING = "31 10 2012 20:50:44";
private final SimpleDateFormat sdf = new SimpleDateFormat("dd MM yyyy HH:mm:ss");
#Test
public void getWeekDatePair() throws ParseException{
Date date = sdf.parse(TEST_DATE_AS_STRING);
DatePair dp = Util.DateTime.getWeekDatePair(date);
Assert.assertEquals(sdf.format(new Date(dp.getStart())), "08 10 2012 00:00:00");
//java.lang.AssertionError: expected [14 10 2012 00:00:00] but found [07 10 2012 00:00:00]
Assert.assertEquals(sdf.format(new Date(dp.getEnd())), "14 10 2012 00:00:00");
}
#Test
public void getLeapWeekDatePair() throws ParseException {
Date leapDate = sdf.parse(LEAP_WEEK_DATE_AS_STRING);
DatePair dp = Util.DateTime.getWeekDatePair(leapDate);
Assert.assertEquals(sdf.format(new Date(dp.getStart())), "29 10 2012 00:00:00");
//java.lang.AssertionError: expected [04 11 2012 00:00:00] but found [28 10 2012 00:00:00]
Assert.assertEquals(sdf.format(new Date(dp.getEnd())), "04 11 2012 00:00:00");
}
Here is failed test output:
java.lang.AssertionError: expected [04 11 2012 00:00:00] but found [28 10 2012 00:00:00]
at org.testng.Assert.fail(Assert.java:94)
at org.testng.Assert.failNotEquals(Assert.java:494)
at org.testng.Assert.assertEquals(Assert.java:123)
at org.testng.Assert.assertEquals(Assert.java:176)
at org.testng.Assert.assertEquals(Assert.java:186)
at ru.rating.utils.UtilDateTimeTest.getLeapWeekDatePair(UtilDateTimeTest.java:77)
expected [14 10 2012 00:00:00] but found [07 10 2012 00:00:00]
Stacktrace
java.lang.AssertionError: expected [14 10 2012 00:00:00] but found [07 10 2012 00:00:00]
at org.testng.Assert.fail(Assert.java:94)
at org.testng.Assert.failNotEquals(Assert.java:494)
at org.testng.Assert.assertEquals(Assert.java:123)
at org.testng.Assert.assertEquals(Assert.java:176)
at org.testng.Assert.assertEquals(Assert.java:186)
at ru.rating.utils.UtilDateTimeTest.getWeekDatePair(UtilDateTimeTest.java:69)
Here is implementation:
public static DatePair getWeekDatePair(){
return getWeekDatePair(new Date());
}
/**
* This is test method
* */
static DatePair getWeekDatePair( Date date){
Date truncDay = truncate(date.getTime(), Calendar.DAY_OF_MONTH);
Calendar calStart = getCalendarInstance(date, Calendar.DAY_OF_MONTH);
calStart.setTime(truncDay);
calStart.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
Calendar calEnd = Calendar.getInstance();
calEnd.setTime(calStart.getTime());
calEnd.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
return new DatePair(calStart.getTime(), calEnd.getTime());
}
public static Date truncate(long date, int calField) {
Calendar cal = getCalendarInstance(new Date(date), calField);
cal = DateUtils.truncate(cal, calField);
return cal.getTime();
}
static Calendar getCalendarInstance(Date date, int calendarField){
//Calendar cal = Calendar.getInstance();
Calendar cal = new GregorianCalendar(Locale.ENGLISH);
cal.setTime(date);
if(calendarField!=Calendar.HOUR){
cal.set(Calendar.HOUR_OF_DAY, 0);
}
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal;
}
Although we are missing key piece of information here (how is Util.DateTime.getWeekDatePair(java.util.Date) implemented), I suspect that what you do there is instantiating java.util.Calendar using default Locale and then search for first day of the week.
My suspicion came from the fact, that you don't pass the Locale instance to the getWeekDatePair() method.
Now, what is the problem here? Well, the first day of the week depends on the Locale. Therefore when you instantiate the Calendar like this: Calendar.getInstance(), what you in fact do is: Calendar.getInstance(Locale.getDefault(Locale.Category.FORMAT). And of course the first day of the week may differ on two different machines, because the Locales may differ.
For example, first day of the week is Sunday in US, but Monday in Poland (I believe it is like that in Russia, isn't it?) Therefore if you do this test on two different machines, fist of which has Locale set to en-US and second to ru-RU, you may expect different results.
If it is only the problem of tests, you may just as well set default Locale and everything should be working just fine. However, please keep in mind that if you are testing web application, using default Locale is a bad thing, as it will return server Locale rather than the one that comes from web browser (or some user profile if you have one). Should this Locales differ, you might use something that is confusing for end user.
Edit
It is quite obvious why it happens from the implementation, and I gave you the hints previously. Consider this code:
Calendar cal = Calendar.getInstance(Locale.ENGLISH);
System.out.println(sdf.format(cal.getTime()));
// Cloning so that Calendar could be re-used
Calendar calEnd = (Calendar) cal.clone();
// Setting start of the week date
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
System.out.println(sdf.format(cal.getTime()));
calEnd.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
System.out.println(sdf.format(calEnd.getTime()));
This prints (correctly):
13 10 2012 00:00:00
08 10 2012 00:00:00
07 10 2012 00:00:00
Now, let's change the Calendar instantiation to:
Calendar cal = Calendar.getInstance(Locale.forLanguageTag("ru-RU"));
Voila, now you'll see:
13 10 2012 00:00:00
08 10 2012 00:00:00
14 10 2012 00:00:00
To see why this is the correct behavior, let's test this code as well:
System.out.println(cal.getFirstDayOfWeek());
For English Locale, it will return 1 (Sunday) as oppose to 2 (Monday) which is the result for Russian Locales. This code behaves correctly, as it returns Monday and Sunday from given week. The only "problem" is the fact, that week means something else all over the world.
As you can see, it has nothing to do with DateUtils, it is merely related to Calendar's behavior. And because of this code: Calendar cal = new GregorianCalendar(Locale.ENGLISH); the behavior should in fact be consistent, so you should always get an error no matter what machine you are testing the code on. It it is not, I really can't understand why.
Depending on what you are trying to achieve, it may make sense to add Locale as a parameter to your method (and instantiate Calendar accordingly), then write some tests covering few Locales (some Arabic Locale may also be interesting as nobody said first day of the week has to be either Sunday or Monday) or merely modifying test dates so that they match the correct Calendar's behavior.

Categories