I'm teaching myself Java and I am working on this application that will count the days until Christmas. The HOUR_OF_DAY, MONTH, and SECOND values of the GregorianCalendar and Date objects for today and Christmas are all set to zero. By debugging I can see the variable for the difference in days in milliseconds and it gives me a time of 1641599724 milliseconds which comes out to be 18.99999 days but it wont round up to 19 no matter what I try!
I have tried Math.ceil method to try and round up but I can't get it to equal 19.
FIRST: DataUtils class stores/modifies input from the user
package chapter13datesstrings;
import java.util.*;
public class DateUtils {
static final int MILLS_IN_DAY = 24 * 60 * 60 * 1000;
public static Date getCurrentDate(){
GregorianCalendar currentDate = new GregorianCalendar();
currentDate.set(Calendar.HOUR_OF_DAY, 0);
currentDate.set(Calendar.MINUTE, 0);
currentDate.set(Calendar.SECOND, 0);
return currentDate.getTime();
}
public static Date createDate(int year, int month, int day){
GregorianCalendar date = new GregorianCalendar(year, month, day);
return date.getTime();
}
public static Date stripTime(Date date){
GregorianCalendar noTimeDate = new GregorianCalendar();
noTimeDate.setTime(date);
noTimeDate.set(Calendar.HOUR, 0);
noTimeDate.set(Calendar.MINUTE,0);
noTimeDate.set(Calendar.SECOND, 0);
return noTimeDate.getTime();
}
public static double daysDiff(Date date1, Date date2){
date1 = stripTime(date1);
date2 = stripTime(date2);
long longDate1 = date1.getTime();
long longDate2 = date2.getTime();
long longDiff = longDate2 - longDate1;
return (int) (Math.ceil(longDiff / MILLS_IN_DAY));
}
}
SECOND: DateUtilExample class provides input to the DataUtils class
package chapter13datesstrings;
import java.util.*;
import java.text.*;
public class DateUtilExample {
public void thisIsCode(){
GregorianCalendar currentGC = new GregorianCalendar();
int currentYear = currentGC.get(Calendar.YEAR); //sets current year
Date currentDate = DateUtils.getCurrentDate(); //create current date object
Date christmas = DateUtils.createDate(currentYear, Calendar.DECEMBER, 25); //set christmas date
int daysToChristmas = DateUtils.daysDiff(currentDate, christmas); // days until christmas
DateFormat date = DateFormat.getDateInstance(Calendar.LONG);
String formattedToday = date.format(currentDate);
/**** Output Items *****/
System.out.println("Today is " + formattedToday);
System.out.println("Number of Days 'Till Xmas: " + daysToChristmas + " days");
}
}
MAIN METHOD CLASS
package chapter13datesstrings;
import java.util.Date;
import java.text.DateFormat;
public class Chapter13DatesStrings {
public static void theDates(){
DateUtilExample dateUtilExample = new DateUtilExample();
dateUtilExample.thisIsCode();
}
public static void main(String[] args) {
theDates();
}
}
When you divide two integers in Java, the result is rounded down ("truncated") automatically.
The expression longDiff / MILLS_IN_DAY isn't equal to 18.99999, it is equal to 18. Java essentially calculates 18.99999 and then throws everything after the decimal point away, before you can do anything with it. Rounding up with ceil won't help at that point, because you just end up calculating ceil(18) which is just 18.
One solution to this is to cast the numbers to double before you divide them. double's are floating point values, so dividing them does not round the result down. To use doubles, replace
longDiff / MILLS_IN_DAY
with
((double)longDiff) / ((double)MILLS_IN_DAY)
Another solution, which may be more computationally efficient but a little bit less elegant is to simply add 1 to the result. This isn't strictly equivalent, because when you are within a millisecond of midnight the result will be a day more than you expected, but this is essentially unnoticeable. To take this approach, you would replace the line:
return (int) (Math.ceil(longDiff / MILLS_IN_DAY));
with
return longDiff / MILLS_IN_DAY + 1;
Alternatively to what SelectricSimian said,
this is something that can be done in a couple of lines using the Calendar API provided by java.
To simply get the day difference between the current time and a given day, you can use:
public static void main(String[] args) {
System.out.println(getDaysUntil(Calendar.DECEMBER, 25) + " day(s).");
// If the date is December 25th, this will output "365 day(s)"
// If the date is December 24th, this will output "1 day(s)"
}
public static int getDaysUntil(int month, int day) {
/**
* First get a properly formatted calendar representing right now. This
* should include leap years and local. With this calendar, we get the
* day of the year.
*/
Calendar calendar = Calendar.getInstance();
int today = calendar.get(Calendar.DAY_OF_YEAR);
/**
* Now change the day and month of the current calendar to the given day
* and month.
*/
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.DAY_OF_MONTH, day);
int desiredDay = calendar.get(Calendar.DAY_OF_YEAR);
/**
* Then we just get the difference between now and then.
*/
int difference = desiredDay - today;
/**
* If the desiredDay has passed already, or it's currently the
* desiredDay, we need to recalculate the difference.
*/
if (difference <= 0) {
/**
* We start by getting the days until the end of the year.
*/
calendar.set(Calendar.MONTH, 11);
calendar.set(Calendar.DAY_OF_MONTH, 31);
int daysUntilEnd = calendar.get(Calendar.DAY_OF_YEAR) - today;
/**
* Then, move the calendar forward a year and get the day of year
* for the desired day again. We recalculate the number of days just
* in case next year is a leap year.
*/
calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + 1);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.DAY_OF_MONTH, day);
desiredDay = calendar.get(Calendar.DAY_OF_YEAR);
/**
* Finally, just add daysUntilEnd and desiredDay to get the updated
* difference.
*/
difference = daysUntilEnd + desiredDay;
}
return difference;
}
Related
I need to extract the start date and end date from a given year and week and return them as LocalDate:
Example: year / month / week : 2022 / 12 / 49 -> date_begin 05/12/2022 - date_end 11/12/2022 this mean the week 49 of the year 2022 starts from 05/12/2022 and ends on the 11/12/2022. The month is irrelevant, as #rzwitserloot said in the comments. The input is provided in ints int year = 2022 and int week = 49.
How to achieve this?
JSR310-extra had the YearWeek, but the somewhat simpler java.time does not - hence, the simplest way is through the parser even if you don't actually need to parse it:
int weekYear = 2022;
int weekNum = 49;
LocalDate monday = LocalDate.parse(String.format("%04d-W%02d-1", weekYear, weekNum), DateTimeFormatter.ISO_WEEK_DATE);
LocalDate sunday = monday.plusDays(6);
System.out.printf("Week %d of year %d runs from %s to %s\n", weekNum, weekYear, monday, sunday);
NB: The format is e.g. 2022-W49-1; the 1 is for 'monday'. Note that this is weekyears: That means the start date could be in the previous year (e.g. week 1 of certain years starts on december 30th in the previous year), or the end date could be in the next year. This is obvious if you think about it (weeks exist that start in one year and end in the next, and they have to be part of some year's 'week-year' system). Just thought I'd highlight it :)
This solution also works
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.WeekFields;
public class Main {
public static final WeekFields US_WEEK_FIELDS = WeekFields.of(DayOfWeek.SUNDAY, 4);
public static void main(String[] args) {
LocalDate date1 = LocalDate.of(2022, 12, 29);
LocalDate date2 = LocalDate.now();
System.out.println(formatDate(date1));
System.out.println(formatDate(date2));
}
public static int getWeek(LocalDate date) {
return date.get(US_WEEK_FIELDS.weekOfWeekBasedYear());
}
public static int getMonth(LocalDate date) {
return date.getMonthValue();
}
public static int getYear(LocalDate date) {
return date.get(US_WEEK_FIELDS.weekBasedYear());
}
public static String formatDate(LocalDate date) {
int week = getWeek(date);
int month = getMonth(date);
int year = getYear(date);
return year + "/" + month + "/" + week;
}
}
When running I get in the console
2022/12/52
2022/12/49
This question already has answers here:
How do I get difference between two dates in android?, tried every thing and post
(15 answers)
Closed 4 years ago.
How I can get number of days between two dates including time. for example number of days between today 8pm till other day's 8pm? I am using this but it is giving according to day of month
public static int getDaysTillOmer(Date d1, Date d2) {
int daysdiff = 0;
long diff = d2.getTime() - d1.getTime();
long diffDays = diff / (24 * 60 * 60 * 1000);
daysdiff = (int) diffDays;
return daysdiff;
}
Use TimeUnit:
public static int getDaysTillOmer(Date d1, Date d2) {
long diff = d2.getTime() - d1.getTime();
return TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS);
Your calculation (and the implementation in one of the answers) only works for system that run in a timezone that doesn't know daylight saving times. For e.g. the german timezone (where I reside), the duration of 2018-03-24 03:00:00 and 2018-03-25 03:00:00 I think you expect to be one day with the only problem that that particular day only has 23 hours.
If you want to stick with the standard classes, the JVM provides, you can use a Calendar and add day after day to it until the underlying date is after the second date. Here is an example (without sanity checks e.g. that the first date is actually before the second one; you will run into an endless loop in the other case). The example sets the timezone to be used explicitly, so it should show the same result on your system as well:
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class CalcDuration {
public final static void main(String[] args) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("Europe/Berlin"));
Date d1 = sdf.parse("2018-03-24 03:00:00");
Date d2 = sdf.parse("2018-03-25 03:00:00");
System.out.println("duration1: " + getDuration(d1, d2));
}
private static int getDuration(Date d1, Date d2) {
Calendar c = Calendar.getInstance();
c.setTimeZone(TimeZone.getTimeZone("Europe/Berlin"));
c.setTime(d1);
int days = 0;
while (true) {
c.add(Calendar.DAY_OF_YEAR, 1);
if (c.getTime().after(d2)) {
return days;
}
days++;
}
}
}
Using Joda Time do it.
public void calcDays(Date start,Date end) {
Duration d = new Duration(start.getTime(), end.getTime());
System.out.println("Number of days from dates "+d.getStandardDays());
}
Duration is Class from JodaTime
Assuming you are using java.util.Date your algorithm is quite good. I would clean it a little bit.
import java.util.Date;
public static int getDaysTillOmer(Date d1, Date d2) {
long diffDays = (d2.getTime() - d1.getTime()) / (24L * 60 * 60 * 1000);
return (int) diffDays;
}
This logic truncates the number of days to an integer value. That is a time difference of 2 days, 23 hours, and 59 minutes will be converted to: 2 days.
Also, note the value 24 was converted to 24L to prevent promotion to long.
I want to take all Saturday and Sunday from given date range...
my inputs are
Start Date : 01/01/2011
End Date : 01/01/2012
now search date which is in between given start date and end date and day would be Saturday or Sunday.
Please Suggest...
Firstly, I'd recommend using Joda Time if you possibly can. It's a much better date and time API than the one built into Java.
Secondly, unless you're really worried about efficiency I would personally go for the incredibly-simple-but-somewhat-wasteful approach of simply iterating over every day in the time period, and including those which fall on the right days. Alternating between adding one day and adding six days would certainly be more efficient, but harder to change.
Sample code:
import java.util.*;
import org.joda.time.*;
public class Test
{
public static void main(String[] args)
{
List<LocalDate> dates = getWeekendDates
(new LocalDate(2011, 1, 1), new LocalDate(2011, 12, 1));
for (LocalDate date : dates)
{
System.out.println(date);
}
}
private static List<LocalDate> getWeekendDates
(LocalDate start, LocalDate end)
{
List<LocalDate> result = new ArrayList<LocalDate>();
for (LocalDate date = start;
date.isBefore(end);
date = date.plusDays(1))
{
int day = date.getDayOfWeek();
// These could be passed in...
if (day == DateTimeConstants.SATURDAY ||
day == DateTimeConstants.SUNDAY)
{
result.add(date);
}
}
return result;
}
}
I recommend to take a look at this RFC-2445 Java open-source library. You can create a weekly recurrence rule with repeating on Sat and Sun, then iterate over the specified period to get all dates.
I think, you can use following way - it's really simple and you don't need to use other libraries.
Take weekday number (for Monday = 1, Sunday = 7). Then - choose new start date, which is first Sunday occurence -> it is startDate + (7 - weekdayNum). By the same algorithm, you can take last Sunday from interval (by substracting EndDate - weekdayNum - 1, I think). And now you can go in for loop through all occurences (use incremental step 7). Or if you want specific occurence, e.g. 3rd sunday, you can simply do newStartDate + 3 * 7.
I hope, this is clear. I'm not sure, if numbers are correct. Hope this helps for understanding the problem.
Here is the complete example.
Please do suggest if we can make it better.
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
/**
*
* #author varun.vishwakarma
*/
public class FindWeekendsInDateRange {
static HashMap<Integer, String> daysOfWeek=null;
static {
daysOfWeek = new HashMap<Integer, String>();
daysOfWeek.put(new Integer(1), "Sun");
daysOfWeek.put(new Integer(2), "Mon");
daysOfWeek.put(new Integer(3), "Tue");
daysOfWeek.put(new Integer(4), "Wed");
daysOfWeek.put(new Integer(5), "Thu");
daysOfWeek.put(new Integer(6), "Fri");
daysOfWeek.put(new Integer(7), "Sat");
}
/**
*
* #param from_date
* #param to_date
* #return
*/
public static List<Date> calculateWeekendsInDateReange(Date fromDate, Date toDate) {
List<Date> listOfWeekends = new ArrayList<Date>();
Calendar from = Calendar.getInstance();
Calendar to = Calendar.getInstance();
from.setTime(fromDate);
to.setTime(toDate);
while (from.getTimeInMillis() < to.getTimeInMillis()) {
if (daysOfWeek.get(from.get(Calendar.DAY_OF_WEEK)) == "Sat") {
Date sat = from.getTime();
listOfWeekends.add(sat);
} else if (daysOfWeek.get(from.get(Calendar.DAY_OF_WEEK)) == "Sun") {
Date sun = from.getTime();
listOfWeekends.add(sun);
}
from.add(Calendar.DAY_OF_MONTH, 1);
}
return listOfWeekends;
}
public static void main(String[] args) {
String fromDate = "7-Oct-2019";
String toDate = "25-Oct-2019";
System.out.println(FindWeekendsInDateRange.calculateWeekendsInDateReange(new Date(fromDate), new Date(toDate)));
}
}
I'm assuming your start and end dates are given in milliseconds. Loop through the dates and check whether days are 'Saturday' or 'Sunday'. Below I'm returning the total no. of Saturday and Sunday in given date range.
private int totalWeekendDays(long start, long end)
{
int result=0;
long dayInMS = TimeUnit.DAYS.toMillis(1);
for (long i = start; i<=end; i = i + dayInMS)
{
String dayOfTheWeek = (String) DateFormat.format("EEEE", i);
if (dayOfTheWeek.equals("Sunday")||dayOfTheWeek.equals("Saturday"))
{
result = result+1;
}
}
return result;
}
I have two strings which are used to store time in the format hh:mm.I want to the compare these two to know which time is greater.Which is the easiest way to go about this?
Use the SimpleDateFormat and Date classes. The latter implements Comparable, so you should be able to use the .compareTo() method to do the actual comparison. Example:
String pattern = "HH:mm";
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
try {
Date date1 = sdf.parse("19:28");
Date date2 = sdf.parse("21:13");
// Outputs -1 as date1 is before date2
System.out.println(date1.compareTo(date2));
// Outputs 1 as date1 is after date1
System.out.println(date2.compareTo(date1));
date2 = sdf.parse("19:28");
// Outputs 0 as the dates are now equal
System.out.println(date1.compareTo(date2));
} catch (ParseException e){
// Exception handling goes here
}
See the SimpleDateFormat documentation for patterns.
Well, if they're actually hh:mm (including leading zeroes, and in 24-hour format) then you can just compare them lexicographically (i.e. using String.compareTo(String)). That's the benefit of a sortable format :)
Of course, that won't check that both values are valid times. If you need to do that, you should probably parse both times: check the length, check the colon, parse two substrings, and probably multiply the number of hours by 60 and add it to the number of minutes to get a total number of minutes. Then you can compare those two totals.
EDIT: As mentioned in the comments, if you do need to parse the values for whatever reason, personally I would recommend using Joda Time (possibly a cut down version, given the mobile nature) rather than SimpleDateTimeFormat and Date. Joda Time is a much nicer date and time API than the built-in one.
I have written functions for this before in my Android program and I will gladly share the source below.
Functions (will explain later using "how to use" code):
public static void String setFormattedTimeString(final String formatExpr,
final long timeStampInSeconds) {
final Date dateFromTimeStamp = new Date(timeStampInSeconds);
final SimpleDateFormat simpleformat = new SimpleDateFormat(formatExpr);
final String formattedDateInString = simpleformat.format(dateFromTimeStamp);
return formattedDateInString;
}
public static void Calendar setCalendar(final int year, final int month,
final int day) {
final Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.DAY_OF_MONTH, day);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.YEAR, year);
return calendar;
}
public static void double timeDifferenceInDays(final Calendar firstDate,
final Calendar secondDate) {
final long firstDateMilli = firstDate.getTimeInMillis();
final long secondDateMilli = secondDate.getTimeInMillis();
final long diff = firstDateMilli - secondDateMilli;
// 24 * 60 * 60 * 1000 because I want the difference in days. Change
// as your wish.
final double diffDays = (double) diff / (double) (24 * 60 * 60 * 1000);
return diffDays;
}
And this is how I use them to calculate difference (days in this example). In this example I'm assuming you have a timestamp to use, otherwise you can change easily:
// Here you maybe have a timestamp in seconds or something..
// This is ONE Calendar.
final String yearString = MyToolClass.setFormattedTimeString("y", timestamp);
final int year = Integer.parseInt(yearString);
final String monthString = MyToolClass.setFormattedTimeString("M", timestamp);
final int month = Integer.parseInt(monthString);
final String day_in_monthString = MyToolClass.setFormattedTimeString("d",
timestamp);
final int day_of_month = Integer.parseInt(day_in_monthString);
final Calendar calendarOne = MyToolClass.setCalendar(year, month,
day_of_month);
// Same stuff for Calendar two.
// Calculate difference in days.
final double differenceInDays = MyToolClass.timeDifferenceInDays(calendarOne,
calendarTwo);
How can I use the Maya calendar in Java?
Has your calendar run out now? :-)
If you are really looking for a solution this Maya Calendar implementation looks quite good.
It implements a maya Tzolk'in calender using Java's GregorianCalendar. Dates can be retrieved both in Gregorian or Tzolk'in format.
Here are the core parts:
[...]
/** parses Date specified in Long Count format, e.g. "12.19.19.17.19" */
public void parseLongCountDate (String longCountDate) {
String [] components = longCountDate.split("\\.");
try {
if (components.length != 5)
throw new Exception("Expecting 5 numbers separated by dots");
int baktuns = Integer.valueOf(components[0]);
int katuns = Integer.valueOf(components[1]);
int tuns = Integer.valueOf(components[2]);
int winals = Integer.valueOf(components[3]);
int kins = Integer.valueOf(components[4]);
set (baktuns, katuns, tuns, winals, kins);
} catch (Throwable e) {
throw new IllegalArgumentException("Invalid long count date format: "
+ e.getMessage());
}
}
/** Set date to given long count date */
public void set (int baktuns, int katuns, int tuns, int uinals, int kins) {
assert MayaTimeUnit.Kin.toDays (1) == 1;
daysSinceGreatCycle =
MayaTimeUnit.Baktun.toDays (baktuns) +
MayaTimeUnit.Katun.toDays(katuns) +
MayaTimeUnit.Tun.toDays(tuns) +
MayaTimeUnit.Winal.toDays(uinals) +
kins;
}
[...]
/** #return day name number in Tzolk'in calendar, e.g. it returns 0 (Ajaw) for the day "4 Ajaw" */
public Tzolkin toTzolkinDayName () {
// The Tzolk'in date is counted forward from 4 Ajaw.
return Tzolkin.DAYS[(daysSinceGreatCycle + 19) % 20]; // relative to Ajaw
}
/** #return day number in Tzolk'in calendar, e.g. it returns 4 for the day "4 Ajaw" */
public int toTzolkinDayNumber () {
// The Tzolk'in date is counted forward from 4 Ajaw.
return (daysSinceGreatCycle + 4) % 13;
}
[...]
/** #return day name number in Haab calendar, e.g. it returns Yaxkin (5) for the day "14 Yaxk'in" */
public Haab toHaabDayName () {
int d = (daysSinceGreatCycle + 349) % 365;
return Haab.DAYS[d / 20];
}
/** #return day number in Haab calendar, e.g. it returns 14 for the day "14 Yaxk'in" */
public int toHaabDayNumber () {
int d = (daysSinceGreatCycle + 349) % 365;
return d % 20 - 1;
}
[...]
/** #return Gregorian calendar representation of currently set date */
public String toGregorianString () {
Calendar c = toGregorianDate ();
return format.format(c.getTime());
}
/** #return Converts currently defined date into Gregorian calendar */
public Calendar toGregorianDate () {
Calendar c = (Calendar)greatCycleStartDate.clone();
c.add(Calendar.DAY_OF_YEAR, daysSinceGreatCycle);
return c;
}
[...]
In any case: Cool question :-)
The best way of using other calendars/chronologies in Java is the excellent Joda-Time library. It doesn't have a Mayan chronology itself, but you could right your own implementation of the Mayan rules and plug it in. Shouldn't be too onerous.
Use JodaTime. Oops, sorry, just a reflex when reading a question about java.util.Calendar ;-)
There are some Java applets on the web that might be helpful to you.
LOL,
try setting the last selectable date to 21 December 2012 ?
but is does not really end there, it just starts over so you want to start counting again after 21 December 2012?