I have the following code to try and get the current day in seconds since epoch, by removing any seconds after 00:00:00 on any given day:
public void method(Date date) {
...
long dayDate = date.getTime() - (date.getTime() % 86400L);
...
}
For some reason, dayDate is simply being set to date.getTime(), and the mathematical operators are doing nothing here.
How would I go about fixing this?
I'll recommend that you use Joda Time library. It has most of the functions related to date, time and calendar that you'll ever need.
Like Ignacio already pointed out, date.getTime() returns the number of milliseconds since January 1st, 1970, so your line should have been:
long dayDate = date.getTime() - (date.getTime() % 86400000L);
Iif you are planning on creating a new Date with dayDate, make sure that it has the right timezone, e.g. it should be in the UTC/GMT timezone. Otherwise, strange things like this could happen:
Date epoch = new Date(0);
System.err.println(epoch);
which gives on my machine Thu Jan 01 01:00:00 CET 1970 because my dates are by default created in the CET (+1) timezone. So if you would use your code and you would create a new Date instance by using the long you calculated, you would end up with a date not at 0:00 on that day, but at 1:00.
However, without immediately resorting to Joda Time (which may not be an option in your project), you can use a Calendar to get the number of seconds:
// Create the calendar and set the date.
Calendar calendar = new GregorianCalendar();
calendar.setTime(date);
// Set the hours, minutes, etc. to 0.
calendar.set(Calendar.HOUR, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
calendar.set(Calendar.AM_PM, Calendar.AM);
long dayDate = calendar.getTime();
Related
I'm trying to get notifications to send in my Android app. I want to send a different notification every week on certain days of the week.
I've got code written that successfully creates the notification using AlarmManager and BroadcastReceiver. The problem I'm facing is that the notifications are running as soon as the app runs. I've discovered that this is because I'm passing values to the following code:
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.DAY_OF_WEEK, dayofweek);
calendar.set(Calendar.HOUR_OF_DAY, hourofday);
calendar.set(Calendar.MINUTE, dayminute);
calendar.set(Calendar.SECOND, daysecond);
Date date = calendar.getTime();
For example, let's say today is Wednesday, July25. If I pass a 1 for dayofweek, Calendar.Day_OF_WEEK is set to Sunday. The problem is when I do calendar.getTime(), the date is set at Sunday, July 22, in the past and not the next Sunday as I would expect (which would be July 29). So what's happening is the alarm manager is scheduling my notification in the past. Since I'm using alarmManager.setRepeating the notification is going to fire immediately, according to the Android Developers documentation which states:
"If the stated trigger time is in the past, the alarm will be
triggered immediately, with an alarm count depending on how far in the
past the trigger time is relative to the repeat interval."
My question is this: how do I prevent calendar.getTime() from returning a date in the past and return a future date instead?
Using the Calendar.add() method will make sure that the other fields (like DAY_OF_MONTH, MONTH, and so on) roll over properly. You just have to convert from your fixed dayOfWeek value to the difference betwenn today and that day:
calendar.add(Calendar.DAY_OF_WEEK, (dayOfWeek - calendar.get(Calendar.DAY_OF_WEEK) + 7) % 7);
Note that this does not respect the time, i.e. when you give it the weekday of today, but a time in the past, the result will still be in the past. To make sure that the result is always in the future, put in a check after setting the values:
public static Calendar getClosestFutureWeekday(int dayOfWeek, int hour, int minute, int second)
{
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.DAY_OF_WEEK, dayOfWeek);
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, second);
if (calendar.before(Calendar.getInstance()))
{
calendar.add(Calendar.DAY_OF_MONTH, 7);
}
return calendar;
}
Try to use the Date class to set the dates. Here are examples of getting the date a week from now and a week ago.
Using cal.add(); will add the days onto the calendar instead of using cal.set();
A week from today:
Date today = Calendar.getInstance().getTime();
Calendar cal = Calendar.getInstance();
cal.setTime(today);
cal.add(Calendar.DATE, 7);
A week ago:
Date today = Calendar.getInstance().getTime();
Calendar cal = Calendar.getInstance();
cal.setTime(today);
cal.add(Calendar.DATE, -7);
Check the date after it is produced and if it is in the past add 7 days to it:
Long currentDateTime = System.currentTimeMillis();
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(currentDateTime);
calendar.set(Calendar.DAY_OF_WEEK, dayofweek);
calendar.set(Calendar.HOUR_OF_DAY, hourofday);
calendar.set(Calendar.MINUTE, dayminute);
calendar.set(Calendar.SECOND, daysecond);
if (calendar.getTimeInMillis() < currentDateTime) {
calendar.add(Calendar.DAY_OF_MONTH, 7);
}
Date date = calendar.getTime();
If you can move on from obsolete java.util.Calendar to Java 8 java.time.* classes, please do yourself a favor and do so. I'm assuming Android means you can't.
The reason why setting the calendar to Sunday doesn't advance the date as you thought but instead goes back in time, is because of first day of week conventions. Not all cultures think that Monday is the first day of the week. Some believe Sunday is. Others take other days too.
For your calendar to behave exactly as you want it to, you must define to it what is the first day of week in your own convention, rather than let it decide on its own.
So, before you do anything else,
calendar.setFirstDayOfWeek(Calendar.MONDAY);
Then, everything else in your program is correct.
This question already has answers here:
Convert Java Date to UTC String
(7 answers)
Closed 5 years ago.
I set my Calendar instance to a UTC date at 00:00 however once i return the result its 1 hour ahead
Calendar cal = Calendar.getInstance(TIMEZONE_UTC, Locale.ENGLISH);
cal.set(2017, 12 - 1, 15);
cal.set(Calendar.AM_PM, Calendar.AM);
cal.set(Calendar.HOUR, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
System.out.println(cal.getTime());
// Fri Dec 15 01:00:00 CET 2017 but should be 00:00:00
I suppose there is the winter/summer offset but I didn't found any description in the Gregorian or Calendar Element to handle this issue
I am getting the impression that you are really after just the date of December 15, 2017, and just wanted to make sure that there is no unexpected hour-of-day? If so, LocalDate from java.time, the modern Java date and time API, is made for you:
LocalDate ld = LocalDate.of(2017, Month.DECEMBER, 15);
System.out.println(ld);
This prints
2017-12-15
No hours, minutes or seconds to be concerned about.
If you do need a date-time at 00:00 UTC (the time I used to call midnight until Basil Bourque’s comment), there are several ways to obtain it. One of them is:
OffsetDateTime utcDateTime = LocalDateTime.of(2017, Month.DECEMBER, 15, 0, 0)
.atOffset(ZoneOffset.UTC);
System.out.println(utcDateTime);
This prints
2017-12-15T00:00Z
The Z in the end means UTC or offset zero. You see that the time of day is 00:00 as you wanted.
The Calendar class that you used in the question is long outdated, so I recommend you don’t use it anymore. java.time, the modern Java date and time API also known as JSR-310, is so much nicer to work with.
What went wrong in your code?
While a Calendar does contain a time zone (you initialized it to TIMEZONE_UTC), a Date (another outdated class) doesn’t. So when you convert to Date using cal.getTime() you lose the information that you wanted the time to be in UTC. Next (and this confuses many), when you print the date, you implicitly call Date.toString(), and this method grabs your JVM’s time zone setting and produces a string with the time in this time zone. So apparently you are (like I am) in a time zone that is at UTC+01:00 in December. The following two date-times denote the same point on the timeline:
Fri Dec 15 01:00:00 CET 2017
Fri Dec 15 00:00:00 UTC 2017
The reason why you see local time printed is you're displaying it via an instance of Calendar using Date.toString() which uses the local timezone(implicitly use the system timezone).
DateTimeFormatter df = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss");
DateTime temp = df.withOffserParsed().parseDateTime("1970-01-02T00:00:00");
Date date = temp.toDate();
DateTime dateTime = new DateTime(date);
long epoch_start_date = dateTime.getMillis();
System.out.println(dateTime);
This prints out 1970-01-02T00:00:00.000+12:00
Is there any way to remove the Time Zone (+12:00 bit) from the dateTime object? It results in the resultant time being 2 Jan 1970 12:00pm rather than the desired 2 Jan 1970 12:00 am.
That's the local time offset from UTC/GMT.
Is there any way to remove the Time Zone (+12:00 bit) from the dateTime object?
Yes, there is a way, but it would result in the wrong time. Assuming you live in Fiji or Kiribati, the time given is the correct time. It's expressed with (+12:00) to indicate which time zone you're in.
It results in the resultant time being 1 Jan 1970 12:00pm rather than the desired 1 Jan 1970 12:00 am.
Not in actual fact, due to the reason I've given. The desired time is 2 Jan 1970, not 1 Jan. The GMT time is 1 Jan at 12:00pm at that moment, and your local time is 2 Jan at 12:00am.
Having given you proper warning, here's how you could work around the time zone:
DateTimeFormatter df = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss");
DateTime temp = df.parseDateTime("1970-01-02T00:00:00");
Date date = temp.toDate();
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int offset = calendar.getTimeZone().getOffset(calendar.getTimeInMillis());
calendar.add(Calendar.MILLISECOND, offset);
calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
DateTime dateTime = new DateTime(calendar);
System.out.println(dateTime);
Just keep in mind, by doing this you may be throwing away any benefit you were getting from Joda expressing time in UTC.
I am using Calendar on a Samsung Note. If I get a new instance of Calendar with Calendar.getInstance() and then call getTimeInMills() without doing anything else I get 1403732346277, which apparently is some value in the very far future.
I need to get a unix style timestamp. Is there some other preferred way to do this? Or some reason why the Calendar is returning this value (i.e. a standard adjustment I can make)?
Unix time represents the number of seconds from the epoch. As the name implies, getTimeInMillis() will return the number of milliseconds from the epoch. You need to divide your milliseconds by 1000 to get unix time.
long unixTime = Calendar.getInstance().getTimeInMillis() / 1000;
getTimeInMillis() returns you the time difference from Jan 1, 1970 with the calendar time in milliseconds.
Here is the calculation:
1403732346277 ms = 1403732346.277 seconds
1403732346.277 s = 389925.6517... hours
389925.6517 h = 16246.90 days
16246.90 days = 44.512 years (simple calculation: I divided by 365 just to get an approx idea. There are leap years in between.)
If you find the difference of current date from Jan 1, 1970, it is 44 years and ~6 months. So it seems to be giving you right time in milliseconds.
Or some reason why the Calendar is returning this value (i.e. a standard adjustment I can make)?
The java.util.Calendar API stores dates and times as the number of milliseconds that have elapsed from epoch (January 1, 1970 midnight UTC).
The number you got from Calendar.getInstance() - 1403732346277 - is what you'd expect. It's the number of milliseconds from epoch up to today at the exact time you called Calendar.getInstance().
If you want to extract more human-readable date/time information from that Calendar object, you can do something like:
Calendar cal = Calendar.getInstance();
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH);
int day = cal.get(Calendar.DAY_OF_MONTH);
int hour = cal.get(Calendar.HOUR_OF_DAY);
int minutes = cal.get(Calendar.MINUTE);
I need to get a unix style timestamp. Is there some other preferred way to do this?
As this post points out, you can get UNIX epoch by:
long unixTime = System.currentTimeMillis() / 1000L;
If I was to given a specific java.util.Date, how can I generate a start and end of that given date. For example, I my date is August 25, 2011, then my start date would be August 25, 2011 00 00 00 and my end of date would be August 25, 2011 23 59 59
Background: (Read below if you want to know why I ask this question)
I use JPA to map date to my MySql database like this. I want the date to have time as well, so I use TemoporalType.TIMESTAMP
#Temporal(TemporalType.TIMESTAMP)
private Date dateProcess; //java.util.Date
I need to query all data given a specific date, and since date is stored as above, I need a date range to achieve what I want.
My game plan is to convert java.util.Date to JodaTime#DateTinme, then construct the start and end date there, and convert it back so that I can pass as parameters to JPQL. But it seems that JodaTime is very immutable, I cant seem to see a setter method any where.
A java.util.Date represents an instant in time, with no reference to a time zone or calendar. The same instant will have a very different start/end of day depending on the time zone of the observer.
You could do something like:
DateTime dateTime = new DateTime(date.getTime(), timeZone);
LocalDate localDate = dateTime.ToLocalDate();
DateTime startOfDay = localDate.toDateTimeAtStartOfDay(timeZone);
DateTime startOfNextDay = localDate.plusDays(1).toDateTimeAtStartOfDay(timeZone);
From the last two variables, you can get back to java.util.Date values if you want. Usually they'll both be midnight, but they might not be.
Note that you should use the start of the next day in an exclusive way, rather than the last second of the current day in an inclusive way, in order to avoid missing values such as August 25, 2011 23:59:59.500...
I believe the type you want is DateMidnight. Make a new DateMidnight and pass it the DateTime in question, and it will take the date at midnight in the morning of the same day. You could then also use the plusDays() function to add 1 day to get your end time.
Date date; // your date
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.HOUR, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
Date startDate = calendar.getTime();
calendar.set(Calendar.HOUR, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
Date endDate = calendar.getTime();