input list
from date ex) 2020-10-01
to date ex) 2020-10-30
List [day of week] ex) [sun,mon....]
List [week] ex) [1,4,5]
I would like to know how to get a specific day of the week between the two dates.
Thank.
from date ex) 2020-10-01 to date ex) 2020-10-30
Your input string is already in the ISO8601 format for date and therefore it can be parsed without providing a DateTimeFormatter explicitly. In order to get the output string in a custom format (e.g. yyyy-MM-dd), you need to format the date object using DateTimeFormatter.
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
String inputStrDate = "2020-10-01";
LocalDate date = LocalDate.parse(inputStrDate);
String outputStrDate = date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
System.out.println(outputStrDate);
}
}
Output:
2020-10-01
However, if your input is some other format, you will need to use DateTimeFormatter in order to parse it to a date object.
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
// Formatter for input string
DateTimeFormatter inputFormat = DateTimeFormatter.ofPattern("dd-MM-yyyy");
String inputStrDate = "10-01-2020";
LocalDate date = LocalDate.parse(inputStrDate, inputFormat);
// Formatter for output string
DateTimeFormatter outputFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String outputStrDate = date.format(outputFormat);
System.out.println(outputStrDate);
}
}
Output:
2020-10-01
Learn more about date-time API from Trail: Date Time.
for(LocalDate d = fromDate; !d.isAfter(toDate); d = d.plusDays(1)) { // 일정 시작 ~ 끝 loop
for (Integer wf : weekOfMonth) {
for (Integer df : dayOfWeek) {
offDay = d.with(fieldWeek, wf)
.with(fieldDay, df);
if (d.getMonth() == offDay.getMonth() && !offDays.contains(offDay)) {
offDays.add(offDay);
}
}
}
}
Sorry for asking the wrong question.
And thank you very much.
I've already made it, but I've studied your code.
java.time
I too recommend that you use java.time, the modern Java date and time API, for your date work. My shot is:
LocalDate fromDate = LocalDate.of(2020, Month.OCTOBER, 1);
LocalDate toDate = LocalDate.of(2020, Month.OCTOBER, 30);
List<DayOfWeek> daysOfWeek = List.of(DayOfWeek.SUNDAY, DayOfWeek.MONDAY);
List<Integer> weeks = List.of(1, 4, 5);
if (! YearMonth.from(fromDate).equals(YearMonth.from(toDate))) {
throw new IllegalStateException("Covering more than one month is not yet supported");
}
WeekFields wf = WeekFields.SUNDAY_START;
for (int week : weeks) {
for (DayOfWeek dow : daysOfWeek) {
LocalDate date = fromDate.with(wf.weekOfMonth(), week)
.with(wf.dayOfWeek(), dow.get(wf.dayOfWeek()));
// Is date inside interval?
if (! (date.isBefore(fromDate) || date.isAfter(toDate))) {
System.out.println(date);
}
}
}
Output:
2020-10-18
2020-10-19
2020-10-25
2020-10-26
The dates printed are Sunday and Monday of weeks 4 and 5 of October defining weeks in the American way where the week begins on Sunday (since you mentioned Sunday first in your example list) and week 1 is the week of October 1. Sunday and Monday of week 1 are not printed because they fall before October 1, that is, in September.
Consider which week scheme you require. You may use for example WeekFields.ISO or WeekFields.of(Locale.getDefault()).
I am finding the week first, then the day of week, because to me this is the natural way. I need to use the WeekFields object for both adjustments to make sure that the chosen week scheme is respected.
If you need to cover more than one calendar month, iterate over the months and do the same for each. Also check that the result date falls within the month so duplicates near month borders are ignored.
Related
I am getting week number and year from DB(using function DATE_PART('week',alarm_date - (interval '1 days') * 0) AS week, DATE_PART('year',alarm_date) AS yearNo , ISO compliant) and on the basis of week number and year i want to calculate weekStartDate and weekEndDate between user provided startdate and end date with week start date for example {"startDate":"2021-12-28","endDate":"2022-01-06","weekStartDay":"Sunday"}
private String getWeek(LocalDate startTime, LocalDate endTime, int yearNo, int weekNumber, int weekStartDay){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Calendar cal = Calendar.getInstance();
// make it ISO compliant since postgres is using ISO time to calculate week number
cal.setMinimalDaysInFirstWeek(4);
cal.set(Calendar.YEAR, yearNo);
cal.set(Calendar.WEEK_OF_YEAR, weekNumber);
//ISO week starts on Monday and ends on Sunday
cal.set(Calendar.DAY_OF_WEEK, weekStartDay);// weekStartDay configurabale, as per
//user input Calendar.SUNDAY or Calendar.MONDAY or Calendar.TUEDAY; etc
String weekStartDate = sdf.format(cal.getTime());
cal.add(Calendar.DATE, 6);
String weekEndDate = sdf.format(cal.getTime());
LocalDate weekStart = LocalDate.of(Integer.valueOf(weekStartDate.substring(0, 4)),
Integer.valueOf(weekStartDate.substring(5, 7)), Integer.valueOf(weekStartDate.substring(8)));
if(weekStart.isBefore(startTime)) {
weekStart = startTime;
}
LocalDate weekEnd = LocalDate.of(Integer.valueOf(weekEndDate.substring(0, 4)),
Integer.valueOf(weekEndDate.substring(5, 7)), Integer.valueOf(weekEndDate.substring(8)));
if(weekEnd.isAfter(endTime)) {
weekEnd = endTime;
}
String weekStr = weekStart.toString()+"_"+weekEnd.toString();
return weekStr;
}
But when weekStartDay falls in lastweek of previous year then it gives the wrong vale of weekStartDate and weekStartEnd so please suggest me how to set yearnumber in java
Avinash, not the full answer but in-line with what Tom mentioned. A lot of convinient date time API's can be used since Java-8. Please feel free to customize this approach for the exact logic you may need
import java.time.DayOfWeek;
import java.time.temporal.ChronoField;
import java.time.temporal.IsoFields;
import static java.time.temporal.IsoFields.WEEK_OF_WEEK_BASED_YEAR;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.temporal.TemporalAdjusters;
public class SO75013931 {
public static void main(String[] args) {
System.out.println(getWeekStart(LocalDate.parse("2021-12-28"),DayOfWeek.SUNDAY));
System.out.println(getWeekEnd(LocalDate.parse("2021-12-28"),DayOfWeek.SUNDAY));
}
//28-12-2021 TO 01-01-2022 && 02-01-2022 to 06-01-2022
private static String getWeekStart(LocalDate localDate, DayOfWeek weekStartDay) {
LocalDate weekStart = localDate.with(TemporalAdjusters.previous(weekStartDay));
return weekStart.isBefore(localDate) ? localDate.toString(): weekStart.toString();
}
private static String getWeekEnd(LocalDate localDate, DayOfWeek weekStartDay) {
LocalDate weekEnd = localDate.with(TemporalAdjusters.next(weekStartDay.minus(1)));
return weekEnd.isBefore(localDate) ? localDate.toString(): weekEnd.toString();
}
}
This would give
2021-12-28
2022-01-01
Again, the idea was to recommend usage of these API's as opposed to older util API's
Is there an easy/direct way to use a DateTimeFormatter pattern to get the next LocalDateTime time that matches that pattern?
I'd like to use this to easily get the next time that an event should happen (could be daily, weekly, monthly, etc.). For example, if an event happens at "Monday 12:00 AM", I would like to get a LocalDateTime for the next Monday at 12:00 AM.
/**Get next LocalDateTime that matches this input
*
* #param input a String for time matching the pattern: [dayOfWeek ][dayOfMonth ][month ][year ]<timeOfDay> <AM/PM>
* #return LocalDateTime representing the next time that matches the input*/
public LocalDateTime getNextTime(String input) {
LocalDateTime currentTime = LocalDateTime.now();
DateTimeFormatter format = DateTimeFormatter.ofPattern("[eeee ][d ][MMMM ][u ]h:m a");
TemporalAccessor accessor = format.parse(input);
// TODO somehow get the next time (that's after currentTime) that matches this pattern
// LocalDateTime time = ???
return time;
}
I can't just do LocalDateTime.from(accessor) because there might not be a year, month, or day of month specified in the input.
To clarify, here are some examples of what I would like:
// if current date is Friday, January 1st, 2021 at 12:00 PM
// this should return a LocalDateTime for Monday, January 4th, 2021 12:00 AM
getNextTime("Monday 12:00 AM");
// should return Saturday, January 2nd, 2021 12:00 AM
getNextTime("12:00 AM");
// should return Tuesday, January 5th, 2021 12:00 AM
getNextTime("5 January 12:00 AM");
// should return Friday, January 8th, 2021 12:00 PM (must be AFTER current time)
getNextTime("Friday 12:00 PM");
No, there is neither an easy nor a direct way to do what you are asking for. It involves quite a bit of coding. You basically have got 16 cases because each of year, month, day of month and day of week may or may not be present. And you more or less will have to handle each case separately.
Also there may not be such a next time. If the year is 2019 there isn’t. If the string is Friday 12 January 2021 2:00 AM, there isn’t because 12 January is a Tuesday, not a Friday.
private static DateTimeFormatter format = DateTimeFormatter
.ofPattern("[eeee ][uuuu ][d ][MMMM ][uuuu ]h:m a", Locale.ENGLISH);
// input = [dayOfWeek] [dayOfMonth] [month] [year] <timeOfDay> <AM/PM>
public static LocalDateTime next(String text) {
TemporalAccessor accessor;
try {
accessor = format.parse(text);
} catch (DateTimeParseException dtpe) {
return null;
}
LocalDateTime now = LocalDateTime.now(ZoneId.systemDefault());
LocalTime parsedTime = LocalTime.from(accessor);
LocalDate earliest = now.toLocalDate();
if (parsedTime.isBefore(now.toLocalTime())) {
earliest = earliest.plusDays(1);
}
return resolveYearMonthDomDow(earliest, accessor).atTime(parsedTime);
}
private static LocalDate resolveYearMonthDomDow(LocalDate earliest, TemporalAccessor accessor) {
if (accessor.isSupported(ChronoField.YEAR)) {
Year parsedYear = Year.from(accessor);
if (parsedYear.isBefore(Year.from(earliest))) {
return null;
}
return resolveMonthDomDow(parsedYear, earliest, accessor);
} else {
Year candidateYear = Year.from(earliest);
while (true) {
LocalDate resolved = resolveMonthDomDow(candidateYear, earliest, accessor);
if (resolved != null) {
return resolved;
}
candidateYear = candidateYear.plusYears(1);
}
}
}
private static LocalDate resolveMonthDomDow(Year year, LocalDate earliest, TemporalAccessor accessor) {
if (accessor.isSupported(ChronoField.MONTH_OF_YEAR)) {
YearMonth knownYm = year.atMonth(accessor.get(ChronoField.MONTH_OF_YEAR));
if (knownYm.isBefore(YearMonth.from(earliest))) {
return null;
}
return resolveDomDow(knownYm, earliest, accessor);
} else {
YearMonth candidateYearMonth = YearMonth.from(earliest);
if (candidateYearMonth.getYear() < year.getValue()) {
candidateYearMonth = year.atMonth(Month.JANUARY);
}
while (candidateYearMonth.getYear() == year.getValue()) {
LocalDate resolved = resolveDomDow(candidateYearMonth, earliest, accessor);
if (resolved != null) {
return resolved;
}
candidateYearMonth = candidateYearMonth.plusMonths(1);
}
return null;
}
}
private static LocalDate resolveDomDow(YearMonth ym, LocalDate earliest, TemporalAccessor accessor) {
if (accessor.isSupported(ChronoField.DAY_OF_MONTH)) {
int dayOfMonth = accessor.get(ChronoField.DAY_OF_MONTH);
if (dayOfMonth > ym.lengthOfMonth()) {
return null;
}
LocalDate resolved = ym.atDay(dayOfMonth);
if (resolved.isBefore(earliest)) {
return null;
} else {
return resolveDow(resolved, accessor);
}
} else {
LocalDate candidateDate = earliest;
if (YearMonth.from(earliest).isBefore(ym)) {
candidateDate = ym.atDay(1);
}
while (YearMonth.from(candidateDate).equals(ym)) {
LocalDate resolved = resolveDow(candidateDate, accessor);
if (resolved != null) {
return resolved;
}
candidateDate = candidateDate.plusDays(1);
}
return null;
}
}
private static LocalDate resolveDow(LocalDate date, TemporalAccessor accessor) {
if (accessor.isSupported(ChronoField.DAY_OF_WEEK)) {
if (date.getDayOfWeek().getValue() == accessor.get(ChronoField.DAY_OF_WEEK)) {
return date;
} else {
return null;
}
} else {
return date;
}
}
Let’s try it out:
String input = "Monday 12:00 AM";
// get the next time that matches this pattern
LocalDateTime time = next(input);
System.out.println(time);
Output when I ran just now (Monday Januar 11, 2021 in the evening):
2021-01-18T00:00
So next Monday. Looks right.
For a different example, showing that leap years are respected:
String input = "Wednesday 29 February 12:00 AM";
2040-02-29T00:00
There are most probably bugs in my code, but the basic idea is working.
The time of day poses no problem. The challenge is with the date. I am using the time of day to determine whether today’s date is an earliest candidate. If the time now is already past the time in the string, the earliest possible date is tomorrow. For your example string, Monday 12:00 AM, this will practically always be the case: it is always after 12 midnight.
You had got an ambiguity in Monday 25 12:00 AM since 25 may be a year (a couple of millennia ago) or a day of month. I solved it by insisting on a four digit year. So if a number in the beginning or right after a day of week has four digits, it’s a year, otherwise it’s a day of month. The formatter I use looks funny, the year comes twice. I needed this to force the parsing to try year before trying day of month, or it would sometimes have taken a four digit number to be day of month. This in turn means that the formatter accepts a few formats too many. I figure it won’t be a problem in practice.
Provided your input is well formatted and is always in English, you could split your input at the first space and use it as follows:
import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.Locale;
public class Example {
public static void main(String[] args) {
LocalDateTime desiredDay = getNextDayTime("Friday 12:00 AM");
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd.MM.yyyy hh:mm a");
System.out.println(dtf.format(desiredDay));
}
public static LocalDateTime getNextDayTime(String input){
String[] splited = input.split(" ", 2);
LocalTime localTime = LocalTime.parse(splited[1], DateTimeFormatter.ofPattern("hh:mm a", Locale.US));
LocalDateTime dateTime = LocalDateTime.now().with(localTime);
LocalDateTime desiredDay = dateTime.with(TemporalAdjusters.next(DayOfWeek.valueOf(splited[0].toUpperCase())));
return desiredDay;
}
}
I'm trying to complete the task named Java Date and Time on HackerRank.
Task
You are given a date. You just need to write the method, getDay, which
returns the day on that date.For example, if you are given the date,
August 14th 2017, the method should return MONDAY as the day on that
date.
I tried my best to do the task but I get either the null result or NullPointerException error. I wonder where do I do wrong. Below is my code:
Thanks in advance!
My Code:
import java.util.*;
public class Solution {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String month = in.next();
String day = in.next();
String year = in.next();
System.out.println(getDay(day, month, year));
}
public static String getDay(String day, String month, String year) {
Calendar cal = Calendar.getInstance();
cal.set(Integer.valueOf(year), (Integer.valueOf(month) - 1), Integer.valueOf(day));
return cal.getDisplayName(cal.get(Calendar.DAY_OF_WEEK), Calendar.LONG, Locale.getDefault());
}
}
Your return is off; you don't want cal.get in the first column of cal.getDisplayName. Currently, I get the month name with your code. Change that to
return cal.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.getDefault());
And call it like
public static void main(String[] args) {
System.out.println(getDay("14", "8", "2017"));
}
And I get (as expected)
Monday
In new code, I would prefer the new classes in java.time (Java 8+), and a DateTimeFormatter - like,
public static String getDay(String day, String month, String year) {
int y = Integer.parseInt(year), m = Integer.parseInt(month), d = Integer.parseInt(day);
return java.time.format.DateTimeFormatter.ofPattern("EEEE")
.format(LocalDate.of(y, m, d));
}
java.time.LocalDate
The modern approach uses the java.time classes.
Import java.time.* to access LocalDate & DayOfWeek classes.
Write getDay method which should be static because it is called in main method.
Retrieve localDate by using of method which takes 3 arguments in "int" format.
convert the getDay method arguments in int format.
finally retrieve name of that day using getDayOfWeek method.
There is one video on this challenge.
Java Date and Time Hackerrank
LocalDate // Represent a date-only value, without time-of-day and without time zone.
.of( 2018 , 1 , 23 ) // Pass year-month-day, 1-12 for January-December.
.getDayOfWeek() // Obtain a `DayOfWeek` enum object.
.getDisplayName( // Automatically localize the name of the day-of-week.
TextStyle.FULL , // How long or abbreviated.
Locale.US // Or Locale.CANADA_FRENCH or so on.
) // Returns `String` such as `Monday` or `lundi`.
For Java 6 & 7, see the ThreeTen-Backport project. For earlier Android, see the ThreeTenABP project.
if you want to use LocalDate, you can use it this way
import java.time.LocalDate;
public static String getDay(int month, int day, int year) {
return LocalDate.of(year, month, day).getDayOfWeek().name();
}
public static String getDay(int month, int day, int year) {
String res= java.time.format.DateTimeFormatter.ofPattern("EEEE")
.format(java.time.LocalDate.of(year, month, day));
return res; }
must use java.time.LocalDate, if u will use direct LocalDate its show compile time error i.e cannot find symbol, so plz use java.time.
You can use new Java8 DateTime API.
public static String getDay(int day, int month, int year)
{
LocalDate dt=LocalDate.of(year, month, day);
System.out.println("day: " + dt.getDayOfWeek().toString());
return dt.getDayOfWeek().toString();
}
A LocalDate is a date without time of day, so fine for our purpose. The of factory method constructs the date that we want. Contrary to the Calendar class used in the question it numbers the months sanely from 1 for January through 12 for December. A LocalDate has a getter for day of week. It returns a constant from the DayOfWeek enum whose toString method gives us a nice readable string such as MONDAY, again in contrast to what we get from Calendar.
public static String findDay(int month, int day, int year) {
Calendar cal = Calendar.getInstance();
cal.set(year, (month - 1), day);
String dayOfWeek = cal.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.getDefault());
return dayOfWeek.toUpperCase();
}
Formatting data and time using java.util date and calendar as follows, where it needed to handle an exception with java.text.SimpleDateFormat in java 7.
public static void main(String[] args){
String inputDateStr = String.format("%s/%s/%s", 23, 04, 1995);
Date inputDate = null;
try {
inputDate = new SimpleDateFormat("dd/MM/yyyy").parse(inputDateStr);
} catch (ParseException ex) {
Logger.getLogger(JavaApplication28.class.getName()).log(Level.SEVERE, null, ex);
}
Calendar calendar = Calendar.getInstance();
calendar.setTime(inputDate);
String dayOfWeek = calendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.US).toUpperCase();
System.out.println(dayOfWeek);
}
Formatting date and time using java.time classes in java 8 as follows and it is immutable and thread-safe.
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
LocalDateTime dateObj = LocalDateTime.now();
System.out.println("Before formatting: " + dateObj);
DateTimeFormatter formatObj = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss");
String formattedDate = dateObj.format(formatObj);
System.out.println("After formatting: " + formattedDate);
}
}
I have method that can take 2 different types of date formats:
MM/YY (credit card expiration date)
yyyyMMdd (funding expiration date)
Credit card expiration date is considered expired on the last day of that month. So, if cc date is May, 2017 (05/17), this cc is considered expired on 31th of May.
Funding expiration date will expire on the day it says it expires. So, if I am looking at it on the same day, it should return TRUE as funding has expired.
This is my code:
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Date;
public static boolean dateHasExpired(String dateInput)
{
LocalDate d = LocalDate.now();
LocalDate dateParsed = null;
if (dateInput.contains("/"))
{
int iYear = Integer.parseInt(dateInput.substring(dateInput.indexOf("/") + 1));
int iMonth = Integer.parseInt(dateInput.substring(0, dateInput.indexOf("/")));
int daysInMonth = LocalDate.of(iYear, iMonth, 1).getMonth().maxLength();
dateInput = iMonth+"/"+daysInMonth+"/"+iYear;
}
else
{
dateInput = ConvertDate(dateInput, "yyyyMMdd", "MM/dd/yyyy");
}
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("MM/dd/yyyy");
dateParsed = LocalDate.parse(dateInput, dateTimeFormatter);
return d.compareTo(dateParsed) <= 0;
}
public static String ConvertDate(String dateValue, String currentFormat, String requiredFormat)
{
SimpleDateFormat inFormatter = new SimpleDateFormat(currentFormat);
SimpleDateFormat outFormatter = new SimpleDateFormat(requiredFormat);
String outDate = "";
try
{
java.util.Date date = inFormatter.parse(dateValue);
outDate = outFormatter.format(date);
}
catch (ParseException e) {
ErrorLogger.logError ( e );
}
return outDate;
}
Does anyone know of better way of doing this?
I also noticed LocalDate doesn't account for Leap Year, so Feb 2015 has 29 days, just like Feb 2016, so my daysInMonth will not be a good number.
Looks like Date is more tollerant than LocalDate when it comes to year being yy and month 5 for month of May.
You can use java.time.YearMonth class, which contains a method that returns the last day of the respective month (and also takes care of leap years):
public static boolean dateHasExpired(String dateInput) {
LocalDate today = LocalDate.now();
LocalDate dateParsed = null;
if (dateInput.contains("/")) {
// parse credit card expiration date
YearMonth ym = YearMonth.parse(dateInput, DateTimeFormatter.ofPattern("MM/yy"));
// get last day of month (taking care of leap years)
dateParsed = ym.atEndOfMonth();
} else {
// parse funding expiration date
dateParsed = LocalDate.parse(dateInput, DateTimeFormatter.ofPattern("yyyyMMdd"));
}
// expired if today is equals or after dateParsed
return ! today.isBefore(dateParsed);
}
With this code (considering that today is May 02, 2017):
System.out.println(dateHasExpired("04/17")); // true
System.out.println(dateHasExpired("05/17")); // false
System.out.println(dateHasExpired("06/17")); // false
System.out.println(dateHasExpired("20170501")); //true
System.out.println(dateHasExpired("20170502")); // true
System.out.println(dateHasExpired("20170503")); // false
Note that atEndOfMonth() method takes care of leap years, so these will also work:
System.out.println(dateHasExpired("02/15"));
System.out.println(dateHasExpired("02/16"));
I've added a System.out.println(dateParsed); in dateHasExpired method, just to check if the date is being parsed correctly. And the output for the dates above are (respectively):
2015-02-28
2016-02-29
And dateHasExpired returns true for both, as expected.
This question already has answers here:
how to get a list of dates between two dates in java
(23 answers)
Closed 6 years ago.
I'm trying to get an array of Dates, while my input is a 'from'/'to' structure.
So my input is:
String date1 = "2014-01-01";
String date2 = "2014-05-01";
My output should be an Arraylist with all dates between date1 and date2.
I've already looked for this, but I could only find questions about the difference between 2 dates:
SimpleDateFormat myFormat = new SimpleDateFormat("dd MM yyyy");
String inputString1 = "23 01 1997";
String inputString2 = "27 04 1997";
try {
Date date1 = myFormat.parse(inputString1);
Date date2 = myFormat.parse(inputString2);
long diff = date2.getTime() - date1.getTime();
System.out.println ("Days: " + TimeUnit.DAYS.convert(diff,TimeUnit.MILLISECONDS));
} catch (ParseException e) {
e.printStackTrace();
}
Any hints or suggestions? All other questions are for iOS or SQL.
Take a look at JodaTime: http://joda-time.sourceforge.net/apidocs/org/joda/time/DateTime.html
DateTime dateTime1 = new DateTime(date1);
DateTime dateTime2 = new DateTime(date2);
List<Date> allDates = new ArrayList();
while( dateTime1.before(dateTime2) ){
allDates.add( dateTime1.toDate() );
dateTime1 = dateTime1.plusDays(1);
}
Below is the code to get array of dates between the two string date.
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
public class DateFormatExample {
public static void main(String[] args) {
// TODO Auto-generated method stub
SimpleDateFormat myFormat = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
String date1 = "2014-01-01";
String date2 = "2014-05-01";
try {
Date d1 = myFormat.parse(date1);
Date d2 = myFormat.parse(date2);
List<Date> allDates = new ArrayList<Date>();
List<String> allDatesString = new ArrayList<String>();
while( d1.before(d2) ){
d1 = addDays(d1, 1);
allDates.add(d1);
allDatesString.add(formatter.format(d1));
}
System.out.println(allDates);
System.out.println(allDatesString);
} catch (ParseException e) {
e.printStackTrace();
}
}
private static Date addDays(Date d1, int i) {
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(d1);
cal.add(Calendar.DATE, 1);
return cal.getTime();
}
}
If you don't want to use third party libraries you can use Calendar:
Check here a working demo.
public static void main(String[] args) throws Exception {
SimpleDateFormat myFormat = new SimpleDateFormat("dd MM yyyy");
String inputString1 = "23 01 1997";
String inputString2 = "27 04 1997";
ArrayList<Date> dates = new ArrayList<Date>();
try {
Date date1 = myFormat.parse(inputString1);
Calendar c1 = DateToCalendar(date1);
Date date2 = myFormat.parse(inputString2);
Calendar c2 = DateToCalendar(date2);
while (!areEqualDate(c1, c2)) {
dates.add(c1.getTime());
System.out.println (c1.getTime());
c1.add(Calendar.DAY_OF_YEAR, 1);
}
} catch (ParseException e) {
e.printStackTrace();
}
// ArrayList<Date> dates >> contain all dates between both given days.
}
private static boolean areEqualDate(Calendar c1, Calendar c2) {
if (c1.get(Calendar.YEAR) != c2.get(Calendar.YEAR)) return false;
if (c1.get(Calendar.MONTH) != c2.get(Calendar.MONTH)) return false;
if (c1.get(Calendar.DAY_OF_YEAR) != c2.get(Calendar.DAY_OF_YEAR)) return false;
return true;
}
public static Calendar DateToCalendar(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return cal;
}
I like JodaTime, but this can also be done without 3rd party libraries by using java.util.Calendar. Given a Calendar object, one can use its add method to increase certain fields of the date while honoring the calendar rules (like adding 1 day to the 31st of January gets you to the 1st of February, not to the 32nd of January).
First get the dates into one Calendar object each, in the correct chronological order so adding is going in the right direction later:
Calendar cStart = Calendar.getInstance(),
cStop = Calendar.getInstance();
if (date1.before(date2)) {
cStart.setTime(date1);
cStop.setTime(date2);
} else {
cStart.setTime(date2);
cStop.setTime(date1);
date1 and date2 are the parsed Date objects from your question, for simplicity's sake.
Next, loop over an "add 1 to day-of-year" instruction until this gets you beyond the stop date:
do {
System.out.println(pretty(cStart));
cStart.add(Calendar.DAY_OF_YEAR, 1);
} while (cStart.before(cStop));
And lastly print the stop date
System.out.println(pretty(cStop));
pretty() is just some mini method sending the calendar through a SDF, like the one you used for parsing the Strings in the first place.
This solution will print the date range, including the start and stop dates, and might need some tweaking around the edge cases (like date1==date2). Can be easily adapted to exclude the start and stop dates. Printing can be swapped for aggregation of course. To get a Date object from the calendar, use the getTime() method (returns a snapshot, not a live reference).
The documentation for the relevant (Gregorian)Calendar can be found here.
In case you are using Guava, there is a very elegant solution to this problem.
Guava has two neat classes, such as Range and ContiguousSet, which implement exactly what you need: first one operates on ranges of values, and second one - is able to convert a range to a set of discrete values.
Example of usage of both (together with JodaTime):
LocalDate start = LocalDate.parse("2015-01-01");
LocalDate end = LocalDate.parse("2019-02-01");
Range<LocalDate> range = Range.closed(start, end); //Creates a "closed" range, that is both dates are inclusive. There are also options like "openClosed", "closedOpen" and "open"
final Set<LocalDate> daySet = ContiguousSet.create(range, LocalDateDomain.INSTANCE); //Create a "virtual" set of days in given the range. "virtual" part means that if you create a set of 10 thousand years, it will not eat your memory at all
for (LocalDate day : daySet) {
//...operation...
}
Personally, I really prefer this way, as it eliminates some problems with understanding closed/open ranges, and makes code much easier to read and understand, while making no impact on performance. Also, it works with any kinds of dates, any libraries (you can swap YodaTime to Java8 Dates or even Java7- Date-based implementation).
Moreover, it allows you to do some neat operations on ranges like intersections, unions, spanning of ranges, incredibly fast "contains" and so on.
Only downsides are:
Dependence on Guava.
Need to create a special "DiscreteDomain" class, which Guava uses to understand where one date ends and other begins.
Example of LocalDateDomain implementation which operates as a bridge between Guava and JodaTime:
public class LocalDateDomain extends DiscreteDomain<LocalDate> {
public static final LocalDateDomain INSTANCE = new LocalDateDomain();
#Override
public LocalDate next(LocalDate value) {
return value.plusDays(1);
}
#Override
public LocalDate previous(LocalDate value) {
return value.minusDays(1);
}
#Override
public long distance(LocalDate start, LocalDate end) {
return Days.daysBetween(start, end).getDays();
}
}
I already know that OP isn't using Java 8 but here's the current solution - Java has been revamped and the new java.time API does every conceivable job in that regard:
//change these values :
LocalDate ld1 = LocalDate.ofEpochDay(0);
LocalDate ld2 = LocalDate.now();
//do NOT change these:
final LocalDate begin = ld1.isBefore(ld2) ? ld1 : ld2;
final LocalDate end = ld2.isAfter(ld1) ? ld2 : ld1;
for (int i = 0; i < begin.until(end, ChronoUnit.DAYS); i++) {
final LocalDate curDate = begin.plusDays(i);
System.out.println("current date : " + curDate);
}
This will output every valid day between the two dates whereas most of the other solutions will also give you invalid ones; heres the thing: temporal calculations need to be done on timezone-independent data - the output on the other hand may very well be timezone and/or chronology -dependent.
Thats why there are packages like java.time.format - simply calculate your time/date values and format them for your chosen region ... thats how its done correctly.
If you need to convert temporal input there are also useful functions in the time-API, i recommend doing a thorough tutorial on the subject, a few good introductions may be this and especially that :
There are two basic ways to represent time. One way represents time in
human terms, referred to as human time, such as year, month, day,
hour, minute and second. The other way, machine time, measures time
continuously along a timeline from an origin, called the epoch, in
nanosecond resolution. The Date-Time package provides a rich array of
classes for representing date and time. Some classes in the Date-Time
API are intended to represent machine time, and others are more suited
to representing human time.