I need to set my GregorianCalendar to a specific hour of day, which is the closest but not future.
If the time now is 21:00, and I need set the hour 22, it will be set to yesterday. But if the time now is 23:00, it will be set for today.
LocalTime hour = LocalTime.of(22, 0);
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("America/Indiana/Marengo"));
ZonedDateTime closestHour = now.with(hour);
if (closestHour.isAfter(now)) { // future
closestHour = now.minusDays(1).with(hour);
}
System.out.println(closestHour);
This printed
2018-02-04T22:00-05:00[America/Indiana/Marengo]
The above is a sketch, not code that is ready for production. You need to supply your desired time zone if it didn’t happen to be America/Indiana/Marengo. And the desired clock hour, of course. If the desired time doesn’t exist, typically in the spring transition to summer time (DST), ZonedDateTime will pick a different time, you will need to detect that and act accordingly.
java.time
You asked for a GregorianCalendar, and I will give you one, but allow me to mention that that class is long outdated and poorly designed, so you shouldn’t want one. I recommend you use java.time, the modern Java date and time API instead.
If you need a GregorianCalendar or just a Calendar object for a legacy API that you cannot change or don’t want to change just now, convert like this:
GregorianCalendar cal = GregorianCalendar.from(closestHour);
Link: Oracle tutorial: Date Time
Related
I have an Instant derived from a Java Calendar, e.g. c.toInstant(), and now in a different location convert that to a custom Date object that needs a day of the month, month, and year. I tried:
if (instance.isSupported(ChronoField.DAY_OF_MONTH) && instance.isSupported(ChronoField.MONTH_OF_YEAR) && instance.isSupported(ChronoField.YEAR)) {
return new com.company.common.Date()
.setDay(instance.get(ChronoField.DAY_OF_MONTH))
.setMonth(instance.get(ChronoField.MONTH_OF_YEAR))
.setYear(instance.get(ChronoField.YEAR));
}
But when I try to compile ErrorProne throws:
...impl/utils/DateUtils.java:21: error: [TemporalAccessorGetChronoField] TemporalAccessor.get() only works for certain values of ChronoField.
.setDay(instance.get(ChronoField.DAY_OF_MONTH))
^
I'm not sure why I can't find an answer for this anywhere, but after some searching I came up with nothing helpful -- though I probably missed something.
Instant is only a timestamp - it only provides seconds, millis and nanos.
If you start with a Calendar instance in the first place you should be able to simply use
calendar.get(Calendar.YEAR)
calendar.get(Calendar.MONTH) + 1
calendar.get(Calendar.DAY_OF_MONTH)
directly to fetch the date values and skip the conversion to Instant.
Note that in Calendar month is a zero-based value. You usually have to add one to get to value one would commonly expect.
If you prefer working with the newer time API you can fetch dates and time from a ZonedDateTime like
Calendar calendar = Calendar.getInstance();
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(calendar.toInstant(), calendar.getTimeZone().toZoneId());
zonedDateTime.getYear();
zonedDateTime.getMonthValue();
zonedDateTime.getDayOfMonth();
I don't see a direct advantage for the example given, beyond getting the "correct" value for month here directly.
It could be useful if you want to do any additional work with the date value beyond just reading its contents.
Generally speaking ZonedDateTime and all other types from the java.time package provide the more robust API and functionality compared to the older Calendar type. Therefore avoid the calendar type for any new code
I am trying to get the current time in 24 hours format by using the code below:
Calendar cal = Calendar.getInstance();
int currentHour = cal.get(Calendar.HOUR);
int currentMinute = cal.get(Calendar.MINUTE);
System.out.println(currentHour);
System.out.println(currentMinute);
My current time is 3.11PM Singapore time. But then when I execute the code above, I am getting 7.09. Any ideas?
I figured the solution already:
Calendar cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getTimeZone("GMT+8"));
currentHour = cal.get(Calendar.HOUR_OF_DAY);
currentMinute = cal.get(Calendar.MINUTE);
The code above returns exactly what I wanted
This will give you the time in 24 hr format
public String getFormattedTime() {
Calendar calendar = Calendar.getInstance();
SimpleDateFormat dateFormatter = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
return dateFormatter.format(calendar.getTime());
}
I can’t be sure from the information you have provided, but the likely cause is that your JVM’s time zone setting is UTC. If you ran your program at, say, 15:09:55 Singapore time, that would print as 7 and 9 in UTC. If you then read your clock in Singapore time a little over a minute later, or read it from a clock that wasn’t in perfect synch with your device (or simulator), it would show 3:11 PM.
The JVM usually picks up its time zone setting from the device, but there can be all sorts of reasons why it is getting it from somewhere else.
As Anton A. said in a comment, you need HOUR_OF_DAY instead of HOUR for 24 hour format (though the time was 7:09 AM in UTC, so this error wasn’t the cause of the unexpected hour in your case).
java.time
The modern way to print the current time is:
System.out.println(LocalTime.now(ZoneId.of("Asia/Singapore")));
The Calendar class that you were using is long outdated and poorly designed. LocalTime is the class from java.time, the modern Java date and time API, that represents the time of day (without time zone, but the now method accepts a time zone to initialize to the current time in that zone). If your Android device is less than new (under API level 26), you will need the ThreeTenABP library in order to use it. See How to use ThreeTenABP in Android Project.
One more link: Oracle tutorial: Date Time explaining how to use java.time.
I work at a company where part of the work for a day is done in the early hours of the next day (i.e. shipping orders). Now for several processes (mainly reporting), we want to let the 'working day' end at 04:00 the next morning so we get more consistent reporting values per day.
We want this to always be at 04:00 the next morning and since we are affected by daylight saving times in our area (Europe - Netherlands) we effectively want a 4 hour shifted variant of our normal timezone 'Europe/Amsterdam' (in our case).
To make this as easy to use for all applications in our company I would like to create a small library that simply contains the code to provide my coworkers to get a modified instance of TimeZone that does this. That way all normal time/date manipulation methods can be used in conjunction with this special time zone.
I did a deep dive into the standard Java 8 code/Javadoc related to the TimeZone/ZoneInfo instances and at this moment I do not understand what the correct field is to change in the returned TimeZone/ZoneInfo instance.
At this point, my best guess is setting the RawOffset to 4 hours, but I'm not sure.
What is the correct way to achieve my goal?
Update:
I had a look at the suggested LocalTime and as I expected: It needs a timezone definition as being what it should use as "Local" when converting an existing timestamp (usually epoch milliseconds) into the "Local" timezone.
Looking at all these classes seems like I'll be using the LocalDate more often than the LocalTime.
Effectively the code I expect to have is something like this:
long epoch = 1525033875230L; // Obtained from some dataset
LocalDate localDate = LocalDateTime
.ofInstant(Instant.ofEpochMilli(epoch),
ZoneId.of("Europe/Amsterdam"))
.toLocalDate();
Where I expect that I need to change that Zone into the 'right one'.
If I have got that correctly, what you really need is a way to convert a milliseconds value since the epoch to a date in a way where days don’t change a 00:00 but not until 04:00.
static ZoneId zone = ZoneId.of("Europe/Amsterdam");
static LocalTime lastShiftEnds = LocalTime.of(4, 0);
public static LocalDate epochMilliToDate(long epoch) {
ZonedDateTime dateTime = Instant.ofEpochMilli(epoch)
.atZone(zone);
if (dateTime.toLocalTime().isAfter(lastShiftEnds)) { // normal date-time
return dateTime.toLocalDate();
} else { // belonging to previous day’s night shift
return dateTime.toLocalDate().minusDays(1);
}
}
Use for example like this:
long epoch = 1_525_050_875_230L;
System.out.println(Instant.ofEpochMilli(epoch));
LocalDate date = epochMilliToDate(epoch);
System.out.println(date);
Output is:
2018-04-30T01:14:35.230Z
2018-04-29
From printing the Instant you can see that the time is after midnight (really 03:14:35.230 in Amsterdam time zone). And the method has correctly deemed that this time belongs to April 29 rather than April 30.
Perhaps I am missing something? On the other hand, if that were me I’d go quite a long way to avoid inventing a time zone that doesn’t exist in real life. Such a time zone would be bound to confuse your coworkers.
I am trying to get some information out of a database and then using that information to get some statistics.
I want to get statistics based on an interval of hours, therefore I have a created a HashSet made up of two Integers hour and data.
In order to get the correct hour I need to get the time out of the database. Therefore I need to create some sort of data / calendar object.
Now since Date has been deprecated I need to find a new way to set the hours.
Does anyone know how i can achive this?
So far this solution works:
Calendar time = Calendar.getInstance();
time.setTime(new Date(2012, 11, 12, 8, 10));
int hour = time.get(Calendar.HOUR);
System.out.println(hour);
But as stated above date has been deprecated so I want to learn the "correct" way to do it.
Using the java.util.Calendar
Calendar c = Calendar.getInstance();
c.set(Calendar.DATE, 2);
c.set(Calendar.HOUR_OF_DAY, 1);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
Or use Joda Time http://joda-time.sourceforge.net/.
Getting Date-Time From Database
Getting date-time from a database has been addressed in hundreds of answers. Please search StackOverflow. Focus on java.sql.Timestamp.
To address the topic of your Question’s title, read on.
Joda-Time
Far easier if you use either Joda-Time or the java.time package bundled with Java 8 (inspired by Joda-Time). The java.util.Date & .Calendar classes bundled with Java are notoriously troublesome, confusing, and flawed.
Time zone is crucial. Unlike java.util.Date, both Joda-Time and java.time assign a time zone to their date-time objects.
Here is some example code to show multiple ways to set the time-of-day on a Joda-Time 2.5 DateTime object.
DateTimeZone zoneMontreal = DateTimeZone.forID( "America/Montreal" ); // Specify a time zone, or else the JVM's current default time zone will be assigned to your new DateTime objects.
DateTime nowMontreal = DateTime.now( zoneMontreal ); // Current moment.
DateTime startOfDayMontreal = nowMontreal.withTimeAtStartOfDay(); // Set time portion to first moment of the day. Usually that means 00:00:00.000 but not always.
DateTime fourHoursAfterStartOfDayMontreal = startOfDayMontreal.plusHours( 4 ); // You can add or subtract hours, minutes, and so on.
DateTime todayAtThreeInAfternoon = nowMontreal.withTime(15, 0, 0, 0); // Set a specific time of day.
Converting
If you absolutely need a java.util.Date object, convert from Joda-Time.
java.util.Date date = startOfDayMontreal.toDate();
To go from j.u.Date to Joda-Time, pass the Date object to constructor of Joda-Time DateTime.
I need to generate a new Date object for credit card expiration date, I only have a month and a year, how can I generate a Date based on those two? I need the easiest way possible. I was reading some other answers on here, but they all seem too sophisticated.
You could use java.util.Calendar:
Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.YEAR, year);
Date date = calendar.getTime();
java.time
Using java.time framework built into Java 8
import java.time.YearMonth;
int year = 2015;
int month = 12;
YearMonth.of(year,month); // 2015-12
from String
YearMonth.parse("2015-12"); // 2015-12
with custom DateTimeFormatter
import java.time.format.DateTimeFormatter;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM yyyy");
YearMonth.parse("12 2015", formatter); // 2015-12
Conversions
To convert YearMonth to more standard date representation which is LocalDate.
LocalDate startMonth = date.atDay(1); //2015-12-01
LocalDate endMonth = date.atEndOfMonth(); //2015-12-31
Possibly a non-answer since you asked for a java.util.Date, but it seems like a good opportunity to point out that most work with dates and times and calendars in Java should probably be done with the Joda-Time library, in which case
new LocalDate(year, month, 1)
comes to mind.
Joda-Time has a number of other nice things regarding days of the month. For example if you wanted to know the first day of the current month, you can write
LocalDate firstOfThisMonth = new LocalDate().withDayOfMonth(1);
In your comment you ask about passing a string to the java.util.Date constructor, for example:
new Date("2012-09-19")
This version of the constructor is deprecated, so don't use it. You should create a date formatter and call parse. This is good advice because you will probably have year and month as integer values, and will need to make a good string, properly padded and delimited and all that, which is incredibly hard to get right in all cases. For that reason use the date formatter which knows how to take care of all that stuff perfectly.
Other earlier answers showed how to do this.
Like
SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM");
Date utilDate = formatter.parse(year + "/" + month);
Copied from Create a java.util.Date Object from a Year, Month, Day Forma
or maybe like
DateTime aDate = new DateTime(year, month, 1, 0, 0, 0);
Copied from What's the Right Way to Create a Date in Java?
The most common sense approach would be to use the Date("YYYY-MM-DD") constructor even though it is deprecated. This is the easiest way to create a date on the fly. Screw whoever decided to deprecate it. Long live Date("YYYY-MM-DD")!!!
Don’t use this answer. Use the answers by Przemek and Ray Toel. As Przemek says, prefer to use a YearMonth for representing year and month. As both say, if you must use a date, use LocalDate, it’s a date without time of day.
If you absolutely indispensably need an old-fashioned java.util.Date object for a legacy API that you cannot change, here’s one easy way to get one. It may not work as desired, it may not give you exactly the date that you need, it depends on your exact requirements.
YearMonth expiration = YearMonth.of(2021, 8); // or .of(2021, Month.AUGUST);
Date oldFashionedDateObject = Date.from(expiration
.atDay(1)
.atStartOfDay(ZoneId.systemDefault())
.toInstant());
System.out.println(oldFashionedDateObject);
On my computer this prints
Sun Aug 01 00:00:00 CEST 2021
What we got is the first of the month at midnight in my local time zone — more precisely, my JVM’s time zone setting. This is one good guess at what your legacy API expects, but it is also dangerous. The JVM’s time zone setting may be changed under our feet by other parts of the program or by other programs running in the same JVM. In other words, we cannot really be sure what we get.
The time zone issue gets even worse if the date is transmitted to a computer running a different time zone, like from client to server or vice versa, or to a database running its own time zone. There’s about 50 % risk that your Date will come through as a time in the previous month.
If you know the time zone required in the end, it will help to specify for example ZoneId.of("America/New_York") instead of the system default in the above snippet.
If your API is lenient and just needs some point within the correct month, you’ll be better off giving it the 2nd of the month UTC or the 3rd of the month in your own time zone. Here’s how to do the former:
Date oldFashionedDateObject = Date.from(expiration
.atDay(2)
.atStartOfDay(ZoneOffset.UTC)
.toInstant());