Subtracting and comparing Dates - java

I have found some similar Que's on SO but had not find the solution.
I have today's Date as following: (Let's say this as Date1 and it's value as 2012-06-22)
Calendar cal = Calendar.getInstance();
SimpleDateFormat dateformatter = new SimpleDateFormat("yyyy-MM-dd");
Date start = cal.getTime();
String currentDate=dateformatter.format(start);
I'm retrieving 4 values from the user:
Particular Date (Assume 5)
Particular Month (Assume 1)
Particular Year (Assume 2012)
No. of days (Assume 7)
So this date, say Date2 becomes 2012-01-05 (yyyy-MM-dd) along with No. of days set to 7.
I want to compare Date 1 and Date 2-No. of days.
I know that by using following snippet, particular no. of days can be subtracted from a calender instance.
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, -7);
But since I'm having Date2 in form of String, I'm not able to follow this approach.
Any help appreciated.
Edit:
From your suggestions, I'll be able to convert String to Date by using parse method of SimpleDateFormat.
Now I've 2 Date Objects.
How do I find Difference between them in terms of days, months, and years?
How to Subtract particular no. of days, say 7, from a particular date, say 2012-01-05?

java.time
The question and the accepted answer have used the java.util Date-Time API and their parsing/formatting API, SimpleDateFormat which was appropriate thing to do using the standard library in 2012. In March 2014, Java 8 introduced the modern Date-Time API which supplanted the legacy API and since then it is highly recommended to use the modern Date-Time API.
Also, quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Requirements copied from your question:
From your suggestions, I'll be able to convert String to Date by using
parse method of SimpleDateFormat.
Now I've 2 Date Objects.
How do I find Difference between them in terms of days, months, and
years?
How to Subtract particular no. of days, say 7, from a
particular date, say 2012-01-05?
Solution using java.time, the modern Date-Time API:
With java.time, you can parse your date string into a LocalDate and then find the Period between this date and the current date (which you obtain with LocalDate.now()). You can also subtract days, months, and years using methods like minusXxx/minus. You have similar methods (plusXxx/plus) for adding these units. Check the documentation of LocalDate to learn more about it.
Note: java.time API is based on ISO 8601 and therefore you do not need a DateTimeFormatter to parse a date-time string which is already in ISO 8601 format (e.g. your date-time string, 2012-06-22).
Demo:
import java.time.LocalDate;
import java.time.Period;
import java.time.temporal.ChronoUnit;
class Main {
public static void main(String[] args) {
LocalDate then = LocalDate.parse("2012-06-22");
LocalDate now = LocalDate.now();
Period period = Period.between(then, now);
System.out.println(period);
System.out.printf("%d years %d months %d days%n",
period.getYears(), period.getMonths(), period.getDays());
// Examples of subtracting date units
LocalDate sevenDaysAgo = now.minusDays(7);
System.out.println(sevenDaysAgo);
// Alternatively
sevenDaysAgo = now.minus(7, ChronoUnit.DAYS);
System.out.println(sevenDaysAgo);
}
}
Output from a sample run:
P10Y6M27D
10 years 6 months 27 days
2023-01-11
2023-01-11
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time.

use SimpleDateFormat to convert String (representing date) to Date
For example :
Date parsedDate = new SimpleDateFormat("yyyy-MM-dd").parse("2012-01-05");

If you can possibly use Joda Time instead of Date/Calendar, do so. It'll make your life easier.
If not, it sounds like you don't want to format the current date - instead, you want to parse Date2 from the user:
Date date2 = dateFormatter.parse(text);
Then you can either create a calendar and subtract a particular number of days, or (if you're talking about elapsed time - you need to think about your behaviour around DST transitions and time zones here) you could just subtract 7 * 24 * 60 * 60 * 1000 milliseconds from date2.getTime().
Fundamentally, you should convert out of a string format as earlier as possible, and only convert to a string format when you really need to - certainly not for comparisons. The natural representation of this data is as a Date or Calendar (assuming you're sticking with the JDK), so work towards getting your data into that representation.
You have several genuine "business" questions to think about though:
Do you want to compare the current date with the date the user's given, or the current date and time with the date the user's given?
What time zone do you want to use for the user's input?
Are you thinking about elapsed days or "logical" days? Because 7 * 24 hours earlier than 1.30am may be 2.30am or vice versa, due to DST transitions
You should answer all those questions before you try to implement your code, as it will affect the representation you use. Also, write unit tests for everything you can think of before you start the implementation.

From my understanding you have two dates now and you want to subtract a particular number of days from date.
First you can use SimpleDateFormat to convert a date to string and string to date
Now to subtract days say 7. you can get time of the date and subtract 7*24*60*60*1000 from it
long daybeforeLong = 7 * 24 * 60 * 60 * 1000;
try {
Date todayDate = new Date();
long nowLong = todayDate.getTime();
Date beforeDate = new Date((nowLong - daybeforeLong));
}
catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

I think you can make use of Comparator provided by java will do work of comparing and sorting the dates too.
here is the link
hope you get what you was looking for..

Related

Get date 1 month ago as yyyy-mm-dd in kotlin [duplicate]

This question already has answers here:
How to reduce one month from current date and stored in date variable using java?
(8 answers)
Closed 1 year ago.
I need to get the date today, and the date one month ago in the format yyyy-mm-dd
To get the date today i have:
val todaysDate = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date()).toString()
Which works as i want:
2021-05-12
However i cannot figure out how to get the date for one month ago in the same format.
I found this function in another thread but it returns "Mon Apr 12 18:24:37 GMT+02:00 2021"
fun getDaysAgo(daysAgo: Int): Date {
val calendar = Calendar.getInstance()
calendar.add(Calendar.DAY_OF_YEAR, -daysAgo)
return calendar.time
}
How can i get the date one month ago in the same format? Thanks.
Edit:
The solution for me was actually very simple using the getDaysAgo function
var daysAgo= SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(getDaysAgo(30)).toString()
However Ole's answer below is probably better and the recommended way. Did not work for me as it requires api level 26 (android) and im on 23.
LocalDate from java.time
Keep and process dates as LocalDate objects, not as strings.
Only when you need to give string output, format your LocalDate into a string in the appropriate format.
Like many in the comments I recommend that you use java.time, the modern Java date and time API, for your date work. In Java code, still keeping processing and formatting separate and trusting you to translate to Kotlin yourself:
public static LocalDate get1MonthAgo() {
return LocalDate.now(ZoneId.systemDefault()).minusMonths(1);
}
public static String formatToIso8601(LocalDate date) {
return date.toString();
}
Assuming that you need to output the date 1 month ago as a string, use the two methods like this:
LocalDate oneMonthAgo = get1MonthAgo();
String oneMonthAgoFormatted = formatToIso8601(oneMonthAgo);
System.out.println(oneMonthAgoFormatted);
When I ran this evening in my time zone, the output was:
2021-04-12
I am exploiting the facts that the format you asked for is ISO 8601, the international format, and that LocalDate (and also the other date-time classes of java.time) produce(s) ISO 8601 format from their toString methods. So we need to specify no formatter. Which is good because fiddling with a format pattern string is always error-prone.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Wikipedia article: ISO 8601

Using instances of GregorianCalendar to determine time passed?

I am working on a project in my CIS 163 class that is effectively a campsite reservation system. The bulk of the code was provided and I just have to add certain functionalities to it. Currently I need to be able to determine how much time has passed between 2 different GregorianCalendar instances (one being the current date, the other being a predetermined "check out") represented by days. I haven't been able to figure out quite how to do this, and was hoping someone here might be able to help me out.
The GregorianCalendar is old and you shouldn't really use it anymore. It was cumbersome and was replaced by the "new" java.time module since Java 8.
Still, if you need to compare using GC instances, you could easily calculate time using milliseconds between dates, like this:
GregorianCalendar date1 = new GregorianCalendar();
GregorianCalendar date2 = new GregorianCalendar();
// Adding 15 days after the first date
date2.add(GregorianCalendar.DAY_OF_MONTH, 15);
long duration = (date2.getTimeInMillis() - date1.getTimeInMillis() )
/ ( 1000 * 60 * 60 * 24) ;
System.out.println(duration);
If you want to use the new Time API, the following code would work.
LocalDate date1 = LocalDate.now();
LocalDate date2 = date1.plusDays(15);
Period period = Period.between(date1, date2);
int diff = period.getDays();
System.out.println(diff);
If you need to convert between the types (e.g. you're working with legacy code), you can do it like this:
LocalDate date3 = gcDate1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
LocalDate date4 = gcDate2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
Also I'm pretty sure this question must've been asked over and over again, so make sure you search properly before asking.
Since you have been forced to use the old and poorly designed GregorianCalendar class, the first thing you should do is convert each of the two GregorianCalendar objects to a modern type. Since Java 8 GregorianCalendar has a method that converts it to ZonedDateTime. Check the documentation, I include a link below.
Now that you’ve got two ZonedDateTime objects, there are different paths depending on your exact requirements. Often one will use Duration.between() for finding the duration, the amount of time between them in hours, minutes, seconds and fraction of second. If you know that you will always need just one of those time units, you may instead use for example ChronoUnit.HOURS.between() or ChronoUnit.MILLISECONDS.between(). If you need to count days, use ChronoUnit.DAYS.between().
If instead you need the time in months and days, you should instead use Period.between().
Links
Documentation:
GregorianCalendar (long outdated, don’t use unless forced to)
Duration
ChronoUnit
Period
Oracle tutorial: Date Time explaining how to use java.time, the modern Java date and time API to which ZonedDateTIme, Duration, ChronoUnit and Period belong.

Hours difference while considering the date

I need to extract the date field from DB and store it in a VO. How can I compare the hours difference from two dates.
For ex:
Let's say date1 = 01-SEP-17 10:00:00 and date2 = 05-SEP-17 12:00:00. I need to compare the two dates and perform some operations like:
if(hours>10){
//do something
}
if(hours<10){
//do something else
}
I'm just able to calculate the difference between the hours (date2-date1) as 2 but how to consider the date too while calculating the difference between the hours?
My present code:
Date dateA = someVO.getDate();
long date = System.currentTimeMillis();
SimpleDateFormat df = new SimpleDateFormat("dd-MM-YY HH:mm:ss");
Date date1 = new Date(date);
Date date2 = df.parse(dateA.toString());
long date1Hours = date1.getHours();
long date2Hours = date2.getHours();
long dateDiff = date1Hours-date2Hours;
if(dateDiff>10){
//something
}
else if(dateDiff<10){
//something else
}
Easy enough to do using the new Java-Time API added in Java 8:
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("dd-MMM-yy HH:mm:ss")
.toFormatter(Locale.US);
LocalDateTime date1 = LocalDateTime.parse("01-SEP-17 10:00:00", fmt);
LocalDateTime date2 = LocalDateTime.parse("05-SEP-17 12:00:00", fmt);
long hours = ChronoUnit.HOURS.between(date1, date2);
System.out.println(hours);
Output
98
First you need to change the pattern used in SimpleDateFormat, and also use a java.util.Locale to specify that the month name is in English (otherwise it uses the system default locale, and it's not guaranteed to always be English).
Then you get the correspondent millis value of each Date, calculate the difference between them and convert this to hours, using a java.util.concurrent.TimeUnit:
SimpleDateFormat df = new SimpleDateFormat("dd-MMM-yy HH:mm:ss", Locale.ENGLISH);
Date date1 = df.parse("01-SEP-17 10:00:00");
Date date2 = df.parse("05-SEP-17 12:00:00");
// get the difference in hours
long dateDiff = TimeUnit.MILLISECONDS.toHours(date2.getTime() - date1.getTime());
dateDiff will be 98.
If you want to compare with the current date, just use new Date().
Daylight Saving Time issues
There's one problem with this approach. Although it doesn't make a difference for most part of the year, there can be differences due to Daylight Saving Time changes.
By default, SimpleDateFormat uses the JVM default timezone. If between the 2 dates there's a Daylight Saving Time changeover (or just an offset change), the result might be different.
Example: in Africa/Windhoek timezone, in September 3rd 2017, at 2 AM, clocks shifted 1 hour forward, from 2 AM to 3 AM (and the offset changed from +01:00 to +02:00). This means that, at that day, all local times between 2 AM and 2:59 AM don't exist in this timezone (it's like they "skipped" this hour).
So, if the JVM default timezone is Africa/Windhoek, then the difference using the code above will be 97 hours (and not 98).
Even if your JVM default timezone is not Africa/Windhoek, this can still happen, depending on the timezone and the dates involved.
Not only that, but the default timezone can be changed without notice, even at runtime. It's always better to specify which timezone you're working with instead of just relying on the default.
You can't avoid DST effects (unless you use UTC), but at least you can choose which timezone you're going to use instead of relying on the system default (that can be changed without notice).
It's possible to set a timezone in the formatter, so all dates will be parsed taking this timezone into account. In the example below, I'm using Europe/London, but of course you can change to one that best suits your case:
// set Europe/London timezone in the SimpleDateFormat
df.setTimeZone(TimeZone.getTimeZone("Europe/London"));
Now all the parsed dates will be considered to be in London timezone (but remind that DST effects will still be considered - the advantage is that you know what timezone you're using and any changes in the JVM's default won't make your code suddenly start giving different and unexpected results).
Always use IANA timezones names (always in the format Continent/City, like America/Sao_Paulo or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CST or PST) because they are ambiguous and not standard.
You can get a list of all timezones using TimeZone.getAvailableIDs() - then you can choose the one that best suits your case.
If you don't want to consider DST effects, you can use TimeZone.getTimeZone("UTC") - because UTC is a standard without DST changes.
Java new Date/Time API
The old classes (Date, Calendar and SimpleDateFormat) have lots of problems and design issues, and they're being replaced by the new APIs.
If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.
If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it here).
The code below works for both.
The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.
First you need to parse the inputs (using a DateTimeFormatter) and specify in what timezone they are. As the dates also have a timezone, I'm using a ZonedDateTime, which is the best choice for this case.
Then you can easily calculate the difference in hours using a ChronoUnit. In the example below, I'm also using London timezone as an example:
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// case insensitive for month name in all caps
.parseCaseInsensitive()
// date/time pattern
.appendPattern("dd-MMM-yy HH:mm:ss")
// use English locale for month name
.toFormatter(Locale.ENGLISH)
// set a timezone
.withZone(ZoneId.of("Europe/London"));
// parse the dates
ZonedDateTime z1 = ZonedDateTime.parse("01-SEP-17 10:00:00", fmt);
ZonedDateTime z2 = ZonedDateTime.parse("05-SEP-17 12:00:00", fmt);
// calculate the difference in hours
long diffHours = ChronoUnit.HOURS.between(z1, z2);
If you want to use UTC, just change the ZoneId to ZoneOffset.UTC constant. If you want to compare with the current date, just use:
// use the same ZoneId used in the formatter if you want to consider DST effects
ZonedDateTime.now(ZoneId.of("Europe/London"));
Conversions to/from Date
If you still need to work with java.util.Date, it's possible to convert from/to the new API. In Java 8 you can use native methods, and in Java <=7 the ThreeTen Backport has the org.threeten.bp.DateTimeUtils class.
To convert a Date to the new classes:
Date date = // java.util.Date
// convert to zoneddatetime (java 8)
ZonedDateTime z = date.toInstant().atZone(ZoneId.of("Europe/London"));
// convert to zoneddatetime (java 7 ThreeTen Backport)
ZonedDateTime z = DateTimeUtils.toInstant(date).atZone(ZoneId.of("Europe/London"));
To convert a ZonedDateTime back to a date:
// convert to zoneddatetime (java 8)
Date date = Date.from(z.toInstant());
// convert to zoneddatetime (java 7 ThreeTen Backport)
Date date = DateTimeUtils.toDate(z.toInstant());
You've essentially already got the times in milliseconds. You could always just compare the milliseconds directly instead.
long tenHoursInMillis = 36000000;
long dateVOMillis = someVO.getDate().getTime();
long dateSysMillis = System.currentTimeMillis();
if(dateSysMillis - dateAMillis > tenHoursInMillis) {
// do something
}
else if(dateSysMillis - dateAMillis < tenHoursInMillis) {
// do something else
}
// do something when they're equal

Get Date as of 4 hours ago [duplicate]

This question already has answers here:
How to create a Date object, using UTC, at a specific time in the past?
(2 answers)
Closed 5 years ago.
How can I return a Date object of 4 hours less than the current system time in Java?
If you're already on Java 8 or newer:
LocalDateTime fourHoursAgo = LocalDateTime.now().minusHours(4);
Or if you want to take DST (Daylight Saving Time) into account (just in case it coincidentally went into or out DST somewhere the last 4 hours):
ZonedDateTime fourHoursAgo = ZonedDateTime.now().minusHours(4);
Or if you're not on Java 8 yet:
Date fourHoursAgo = new Date(System.currentTimeMillis() - (4 * 60 * 60 * 1000));
And you want to take DST into account:
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.HOUR_OF_DAY, -4);
Date fourHoursAgo = calendar.getTime();
The other answers are correct, but I would like to contribute the modern answer. The modern solution uses java.time, the modern Java date and time API.
Instant fourHoursAgo = Instant.now().minus(Duration.ofHours(4));
System.out.println(fourHoursAgo);
This just printed:
2018-01-31T15:22:21.113710Z
The Z in the end indicates that the time is printed in UTC — at UTC offset zero if you will. The Instant class is the modern replacement for Date, so I recommend you stick to it. The modern API is generally so much nicer to work with, so much cleaner, so much better designed.
Please note the advantages of letting the library class do the subtraction of 4 hours for you: the code is clearer to read and less error-prone. No funny constants, and no readers taking time to check if they are correct.
If you do need an old-fashioned Date object, for example when using a legacy API that you cannot change or don’t want to change, convert like this:
Date oldfashionedDate = Date.from(fourHoursAgo);
Link: Oracle Tutorial trail: Date Time. Of course there are other resources on the internet too, please search.
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.HOUR_OF_DAY, -4);
calendar.getTime();
Convert it to milliseconds, subtract the number of milliseconds in 4 hours, convert it back to a Date.
Calendar c = Calendar.getInstance();
c.add(Calendar.HOUR_OF_DAY, -4);
java.util.Date d = c.getTime();
System.out.println(d);
Calendar c =Calendar.getInstance() ;
c.add(Calendar.HOUR,-4);
Date d = c.getTime();
Use a Calendar object and the add method.
calendar.add(Calendar.HOUR, -4);
See http://download.oracle.com/javase/6/docs/api/java/util/Calendar.html

Java SimpleDateFormat always returning January for Month

I'm working on taking a date value (createWhen) from Active Directory, and translating it into a Java date, for the purposes of getting a list of accounts created between two dates. Everything is working fine, save for one method: the method where I go from the AD Date to the Java date. The method looks like this:
private Date getParsedDate(String givenString) {
System.out.println("Value from AD is: " + givenString);
Date parsedDate = null;
String formattedString = this.formatDateString(givenString);
System.out.println("Formatted String is: " + formattedString);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/DD");
try {
parsedDate = sdf.parse(formattedString);
System.out.println("Final date string is: " + parsedDate.toString());
} catch (ParseException ex) {
ex.printStackTrace();
}
return parsedDate;
}
And, for a single piece of arbitrary data from AD:
Value from AD is: 20050912190509.0Z
Formatted String is: 2005/09/12
Final date string is: Wed Jan 12 00:00:00 EST 2005
Obviously, it's picking up the day and year correctly (and if I choose to include hours/minutes/seconds it includes those correctly as well), but every single date is being placed in January for some reason.
Now, I'm sure that my error is a pretty simple one, but I've rechecked my formatting about ten times, and I'm at the point where I just can't see it any more. Can a second pair of eyes hopefully look over my code and point out where I'm going wrong to get the month so grossly incorrect?
Thanks.
Change the pattern string from "yyyy/MM/DD" to "yyyy/MM/dd"
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
Make sure you don't use 'mm' instead of 'MM' or 'MMM'. As small m denotes minutes and caps M denotes month.
TL;DR
LocalDate parsedDate = OffsetDateTime
.parse("20050912190509.0Z", DateTimeFormatter.ofPattern("uuuuMMddHHmmss.SX"))
.toLocalDate();
This yields a LocalDate of 2005-09-12.
java.time
I am contributing the modern answer. Suhas Phartale’s answer is correct and was a good answer when it was written 7 years ago. Now the notoriously troublesome SimpleDateFormat class is long outdated and we have so much better in java.time, the modern Java date and time API. I warmly recommend you use this instead of the old date-time classes.
Details
It seems from your code that you reformat your string from AD before parsing it. There’s no need for that, the string from AD can be parsed directly. We might have parsed it directly into a LocalDate, but I recommend parsing it into an OffsetDateTime to grab the time and offset from the string; as you can see, this can be directly converted to a LocalDate afterwards. A LocalDate is a date without time of day, so it seems to match your requirements better than the old Date class.
The string is in UTC (denoted by the Z in the end). The above gives you the date from the string, that is the date in UTC. If instead you wanted the date it was in your local time zone when it was September 12 19:05 in UTC:
LocalDate parsedDate = OffsetDateTime.parse(givenString, adDateTimeFormatter)
.atZoneSameInstant(ZoneId.of("America/Coral_Harbour"))
.toLocalDate();
I assumed we have declared the formatter a static field:
private static final DateTimeFormatter adDateTimeFormatter
= DateTimeFormatter.ofPattern("uuuuMMddHHmmss.SX");
In this case the result is the same, for other time zones it will not be. Please substitute your own desired time zone for America/Coral_Harbour. To use the JVM’s time zone setting, specify ZoneId.systemDefault(). Beware, however, that the setting may be changed by other parts of your program or other programs running in the same JVM, so this is fragile.
And the point from Suhas Phartale’s answer is valid in java.time too: format pattern strings are case sensitive, and I needed to use lowercase dd for day of month.
Tutorial
Learn more about java.time in the Oracle tutorial and/or search for other resources on the net.
I am posting this answer because i was redirected from here and above solutions did not resolve my issue
For me the scenario was that after parsing this date "2020-03-01T07:00:00+0530" i was getting the result as 1/2 [dd/MM] which is the format that i wanted, but that result contained the wrong month since the date string clearly indicates the month is 3 [MARCH].
So basically cal.get(Calendar.DAY_OF_MONTH) was returning me 2 instead of actual 3.
And as per docs in MONTH section
"the first month of the year in the Gregorian and Julian calendars is
JANUARY which is 0; the last depends on the number of months in a
year."
so we just need to add a +1 and we would get the actual month. Guess this behavior is there may be to return the names of month from month array or so ?! [January,February,etc..]
Below is a sample of my implementation (my date format in string is "yyyy-MM-dd'T'HH:mm:ssZ"):
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat(Constant.DATE_FORMAT_WITH_TIMEZONE,Locale.ENGLISH);
try {
cal.setTime(Objects.requireNonNull(sdf.parse(forecastList.get(listPosition).fcst_valid_local)));
} catch (ParseException e) {
e.printStackTrace();
}
String s = "%s/%d";
String output = String.format(s,cal.get(Calendar.DAY_OF_MONTH),(cal.get(Calendar.MONTH)+1)));
hope this helps some one.

Categories

Resources