Using date, and date only, in java - java

I'm writing a java program and I have been stuck for quite some while with all the Date, DateTime and so forth parts of Java Programming.
What I want is to have a DATE object only. I have a class:
Deployment.java
public class Deployment {
int id;
LocalDate deviceDeploymentDate; //I'm unsure what this should be
public Deployment(int id, LocalDate deviceDeploymentDate) {
this.id = id;
this.deviceDeploymentDate = deviceDeploymentDate;
}
public Deployment() {
}
public LocalDate getDeviceDeploymentDate() {
return deviceDeploymentDate;
}
public void setDeviceDeploymentDate(LocalDate date) {
this.deviceDeploymentDate = date;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
And I have a Date Picker in my GUI.
From this Date Picker I can get the date in a string format (and also change it to int year, int month and int date if needed ofc). From this I want to store some sort of DATE within my Deployment object, and I do not want the time to be part of this at all.
Question
Which datatype should I use to do this? And how would I do?
Misc
I have shortly looked at Joda Time, but have been unable to create a LocalDate / DateTime type from either the String or integers that I can get from the Date Picker.

Joda-Time is great, but is mostly not needed since the Date-Time API in Java 8 and later. The team behind Joda-Time even advices users on Java 8 or above to use the standard API:
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.
Given this, you should use LocalDate from the standard API, java.time. Your Deployment class can look just like it does now, just make sure to import the correct package (java.time.LocalDate).
Since you have access to the fields (year, month and day), you can use one of the of() methods in the API:
LocalDate.of(year, month, day);
Note that month and day starts with 1, i.e. January is month 1. In the previous Date/Calendar APIs, month counting started with 0, i.e. January was month 0. In other words, be careful if you mix the two APIs.
By the way, java.time has a predefined Month enum that might be handy instead of using integers for months:
LocalDate localDate = LocalDate.of(2012, Month.January, 31);

You can keep using LocalDate(as per David's comment) and use DateTimeFormatter from Joda Time as below to convert String into LocalDate.
final DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyy-MMM-dd");
final LocalDate dt = dtf.parseLocalDate(yourinputString);

Related

How to get epoch of custom date and time in java?

I want an epoch of every day at 12pm. I have tried to make a function that makes a string of date time and has to convert into an epoch but this doesn't work and also it shows 12pm to 0(zero) I don't know why
here's what I have tried but show error:
Calendar now = Calendar.getInstance();
int year = now.get(Calendar.YEAR);
int month=now.get(Calendar.MONTH)+1;
int date=now.get(Calendar.DATE);
String yearInString = String.valueOf(year);
String monthInString=String.valueOf(month);
if(monthInString.length()==1){
monthInString="0"+monthInString;
}
String dateInString=String.valueOf(date);
if(dateInString.length()==1){
dateInString="0"+dateInString;
}
int hour=now.get(Calendar.HOUR);
String hourInString=String.valueOf(hour);
int minute=now.get(Calendar.MINUTE);
String minuteInString=String.valueOf(minute);
if(minuteInString.length()==1){
minuteInString="0"+minuteInString;
}
int second=now.get(Calendar.SECOND);
String secondInString=String.valueOf(second);
String HRD=yearInString+"-"+monthInString+"-"+dateInString+" "+hourInString+":"+minuteInString+":"+secondInString;
System.out.println(HRD);
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS");
LocalDateTime dt = LocalDateTime.parse(HRD, dtf);
Instant instant = dt.toInstant(ZoneOffset.UTC);
System.out.println(instant.toEpochMilli());
and also tried this
Date date1 = dateFormat.parse(HRD);
long epoch = date1.getTime();
System.out.println(epoch);
but show error
Exception in thread "main" java.time.format.DateTimeParseException: Text '2021-10-06 0:29:43' could not be parsed at index 11
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2052)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1954)
at java.base/java.time.LocalDateTime.parse(LocalDateTime.java:494)
at customepoch.main(customepoch.java:35)
java.time
The java.util Date-Time API is outdated and error-prone. It is recommended to stop using it completely and switch to the modern Date-Time API*.
Solution using java.time, the modern Date-Time API: From the OffsetDateTime at 12 pm, you can get the corresponding Instant using OffsetDateTime#toInstant and from this Instant, you can get the epoch milliseconds.
Demo:
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.temporal.TemporalAdjusters;
public class Main {
public static void main(String[] args) {
OffsetDateTime todayAtNoon = OffsetDateTime.of(LocalDate.now(ZoneOffset.UTC), LocalTime.NOON, ZoneOffset.UTC);
OffsetDateTime lastDateOfMonth = todayAtNoon.with(TemporalAdjusters.lastDayOfMonth());
for (OffsetDateTime odt = todayAtNoon; !odt.isAfter(lastDateOfMonth); odt = odt.plusDays(1)) {
System.out.println(odt.toInstant().toEpochMilli());
}
}
}
Output:
1633521600000
1633608000000
1633694400000
...
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time.
* If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time.
What went wrong in your code?
There are already two answers showing you how to obtain the numbers you want. I am not repeating that.
Rather I am posting this answer because I sensed a curiosity: Why did your code show 12 PM as 0 (zero)? Why did you get the error (exception)? This is what I am addressing here.
First as has been said directly or indirectly you were using the Calendar class for obtaining the current time in your time zone. Calendar is poorly designed and long outdated. Don’t do that.
Your conversion from Calendar to Instant was very, very complicated. If you had got a Calendar from some legacy API and wanted to convert it (which you don’t want for your current purpose), all you had needed was:
Instant instant = now.toInstant();
That’s right, since Java 8 Calendar has got a toInstant method for the conversion. The other old date and time classes have got similar conversion methods added.
You tried:
int hour=now.get(Calendar.HOUR);
Calendar.HOUR is for hour within AM or PM from 0 though 11. This explains why you got 0 for 12 PM. Calendar.HOUR_OF_DAY is for hour of day from 0 through 23. It’s just one of the many confusing points about Calendar and one of the many reasons why I recommend you don’t use it.
You prepended month, day of month and minute with 0 to make sure you had got two digits. You didn’t do the same for hour and second. Since your hour was 0, it was only one digit and did not match HH in the format pattern, which requires two digits. This caused the exception that you reported.
You tried this formatter for parsing:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS");
The string you built did not include milliseconds. You should either leave out .SSS or you should add the fraction of second to your string.
This seems to conflict with your intention:
Instant instant = dt.toInstant(ZoneOffset.UTC);
Since you wanted the time in your local time zone, it should have been:
Instant instant = dt.toInstant(ZoneId.systemDefault());
Say you have your local timezone properly set for your JVM so that it is available with ZoneId.systemDefault(). Assume also you start from today (06-Oct-2021). Then your code would be:
public static void main(String[] args) {
LocalDateTime start = LocalDateTime.of(2021, Month.OCTOBER, 6, 12, 0);
for (long i = 0; i < 10; i++) {
System.out.println(
start
.plusDays(i)
.atZone(ZoneId.systemDefault())
.toEpochSecond()
);
}
}

Joda LocalDateTime from LocalDate and string

I have:
a joda LocalDate, so it has no time information and just date
a string which contains time and zone information, like "14:20 CEST"
Either of them can be absent (Scala's Option).
How can I combine these two to get joda LocalDateTime, i.e. entity representing only date and time with no timezone?
To combine these 2 options, the natural way is to use flatMap method like this:
val onlyDateOption: Option[LocalDate] = ???
val timeAndZoneOption: Option[String] = ???
val result: Option[LocalDateTime] = onlyDateOption.flatMap { onlyDate =>
timeAndZoneOption.map { timeAndZone =>
// Some logic here to build the LocalDateTime from onlyDate and timeAndZone
}
}
Which can also be written with for-comprehension in more readible way:
val result: Option[LocalDateTime] = for {
onlyDate <- onlyDateOption
timeAndZone <- timeAndZoneOption
} yield {
// Some logic here to build the LocalDateTime from onlyDate and timeAndZone
}
Now, how to use Joda to build what you're expecting can probably be done in various different ways, one could be:
onlyDate
.toLocalDateTime(LocalTime.MIDNIGHT)
.withHourOfDay(...) // hour extracted from the string somehow
.withMinuteOfHour(...) // minute extracted from the string somehow
I'm not familiar with Joda API, there is probably another easier way
How to combine LocalDate and String using Joda-Time
You have already got an answer treating the use of Option in detail. Here I want to go into more detail with the combination of your LocalDate and your String into a LocalDateTime using Joda-Time. I understand that you are getting a Joda-Time LocalDate from legacy code and need to return a Joda-Time LocalDateTime to legacy code. I am assuming that you know the time zone the abbreviation of which is in the string. I think that you should validate that abbreviation since Central European Time uses the abbreviation CET during the standard time part of the year and CEST during summer time (DST). Excuse my Java code.
DateTimeUtils.setDefaultTimeZoneNames(createTimeZoneNamesMap());
DateTimeFormatter timeFormatter = DateTimeFormat.forPattern("H:mm z");
LocalDate date = new LocalDate(2021, 5, 22);
String timeAndZoneString = "14:20 CEST";
LocalTime time = LocalTime.parse(timeAndZoneString, timeFormatter);
DateTime dateTime = date.toDateTime(time, ZONE);
// Validate time zone abbreviation; take overlap at fall-back into account
String earlierCorrectTimeString = dateTime.withEarlierOffsetAtOverlap()
.toString(timeFormatter);
if (! timeAndZoneString.equals(earlierCorrectTimeString)) {
String laterCorrectTimeString = dateTime.withLaterOffsetAtOverlap()
.toString(timeFormatter);
if (! timeAndZoneString.equals(laterCorrectTimeString)) {
throw new IllegalStateException("Incorrect time zone abbreviation for date");
}
}
LocalDateTime ldt = dateTime.toLocalDateTime();
System.out.println(ldt);
Output:
2021-05-22T14:20:00.000
I have used these two auxiliary declaration:
private static final DateTimeZone ZONE = DateTimeZone.forID("Europe/Paris");
private static Map<String, DateTimeZone> createTimeZoneNamesMap() {
Map<String, DateTimeZone> names = new HashMap<>(4);
names.put("CET", ZONE);
names.put("CEST", ZONE);
return names;
}
The validity of the time on the date is also validated: date.toDateTime() validates that the resulting DateTime would not fall in the gap at the spring-forward and throws an IllegalInstantException: if it would.
If the hours you receive in the string are always two digits, the format pattern string needs to specify this, so HH:mm z.
Please be aware that you are losing information in a corner case: If the time falls in the overlap at fall-back, the time zone abbreviation disambiguates, but the LocalDateTime that you produce is ambiguous. For example the date is 2021-10-31 and the time string is 2:20 CEST. Then we know that the time is in the summer time part of the year, that is, before the clocks are turned back. You return 2021-10-31T02:20:00.000, and the receiver won’t be able to tell whether to understand it as 2021-10-31T02:20:00.000+02:00 (summer time) or 2021-10-31T02:20:00.000+01:00 (standard time).

How to send Date object as parameter in JAVA

I have a Booking Class which has a Date variable in it.
Basically, I want to do add a new variable to ArrayList called "bookings". It works for SSN ,but Date type does not pass in this way. Why is it and what should I do to fix this situation?
Code in my "main"
bookings.add(new Booking(new Date(18,11,2020), SSN));
Here is Booking Class
public class Booking {
private Date bookingDate;
private int SSN;
public Booking(Date bookingDate, int SSN) { // constructor
this.bookingDate=bookingDate;
this.SSN=SSN;
}
}
You are not using the Date constructor properly.
The constructor for Date is in your case:
new Date(int year, int month, int date);
You should be using:
Date date = new Date(120, 11, 18);
Which returns
Fri Dec 18 00:00:00 EST 2020
ALSO: Take note that the year is actually the year - 1900 (e.g, the number of years from 1900).
It is now recommended to use use Calendar.set(year + 1900, month, date, hrs, min) or GregorianCalendar(year + 1900, month, date, hrs, min).
java.time
… and what should I do to fix this situation?
I very strongly recommend that you’re using java.time, the modern Java date and time API, for your dates. The LocalDate class from java.time represents a date without time of day. It’s got a couple of well-working factory methods, so constructing the date that we want is straightforward and trouble-free.
public class Booking {
private LocalDate bookingDate;
private int ssn;
public Booking(LocalDate bookingDate, int ssn) {
this.bookingDate = bookingDate;
this.ssn = ssn;
}
}
Now your main code could be:
bookings.add(new Booking(LocalDate.of(2020, Month.NOVEMBER, 11), ssn));
Many will find the code easier to read if we break it up a bit:
LocalDate newBookingDate = LocalDate.of(2020, Month.NOVEMBER, 11);
Booking newBooking = new Booking(newBookingDate, ssn);
bookings.add(newBooking);
You notice that there are no funny numberings. Year 2020 is 2020, and you may alternatively pass November as the number 11 if you prefer. Isn’t there still the risk of putting the arguments in the wrong order?
LocalDate newBookingDate = LocalDate.of(11, Month.NOVEMBER, 2020);
This throws:
Exception in thread "main" java.time.DateTimeException: Invalid value
for DayOfMonth (valid values 1 - 28/31): 2020
Read the message. It tells us that we put 2020 where the day of month was expected. Enjoy how much more helpful this is than the behaviour of the deprecated Date constructor that you tried to use.
Aside: a note on naming
Variables in Java begin with a lowercase letter, so prefer ssn over SSN. Also when in the domain SSN is an abbreviation and always written in upper case.
Link
Oracle tutorial: Date Time explaining how to use java.time.

last date of previous month returning 30 days for May

I am using the below code to retrieve the last day in the previous month - Ex: May. But it is returning 30 days instead of 31.
The code given below
package net.vcmg.date;
import java.util.Calendar;
import java.util.Date;
import org.apache.commons.lang.time.DateUtils;
public class LastDayPreviousMonth {
public static void main(String[] args) {
Date lastDateOfPreviousMonth = addMonths(lastDayOfTheMonth(today()), -1);
System.out.println("lastDateOfPreviousMonth: "+lastDateOfPreviousMonth);
}
//the below method is from Utils.java
public static Date lastDayOfTheMonth(Date d) {
Calendar cal = Calendar.getInstance();
cal.setTime(d);
int actualMax = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
cal.set(Calendar.DAY_OF_MONTH, actualMax);
return cal.getTime();
}
public static Date addMonths(Date date, int numMonths)
{
return DateUtils.addMonths(date, numMonths);
}
public static Date today()
{
return truncDate(now());
}
public static Date now()
{
// will cut-off milliseconds
return new Date( (System.currentTimeMillis()/1000) * 1000);
}
public static Date truncDate (Date date) {
return DateUtils.truncate(date, Calendar.DATE);
}
}
Here, when i call the lastDateOfPreviousMonth in the main method, it is returning 30 days alone. Not the 31 , May contains 31 days actually. Please help.
Java 8
If you are not constraint to use the old Date it will be better to use the new java.time.LocalDate
LocalDate previousMonth = LocalDate.now().minusMonths(1);
LocalDate start = previousMonth.withDayOfMonth(1);
LocalDate end = previousMonth.withDayOfMonth(previousMonth.lengthOfMonth());
System.out.println(start);
System.out.println(end);
Output
2019-05-01
2019-05-31
Edit
For your implementation, change the order of methods
addMonths - get the current date and provide the previous month addMonths(new Date(), -1)
lastDayOfTheMonth - get the last day of the previous month lastDayOfTheMonth(addMonths(new Date(), -1))
Date lastDateOfPreviousMonth = lastDayOfTheMonth(addMonths(new Date(), -1));
Output
lastDateOfPreviousMonth: Fri May 31 10:46:13 EEST 2019
Try this:
public static void main(String[] args) {
Date lastDateOfPreviousMonth = lastDayOfTheMonth(addMonths(today(), -1));
System.out.println("lastDateOfPreviousMonth: " + lastDateOfPreviousMonth);
}
When you call lastDayOfTheMonth for today() day will be 30. And after minus one month result expected will be 30, not 31.
It’s a logical error in the way you have thought out your program/algorithm. You are first finding the last day of the month, in this case June 30. You are then subtracting 1 month. That gives May 30 regardless of the fact that there are 31 days in May (it’s not explicit from the documentation of DateUtils.addMonths that it works this way, but it uses the poorly designed and outdated Calendar class internally, so this is what we should expect).
Instead do things in the opposite order. First find the previous month:
YearMonth lastMonth = YearMonth.now(ZoneId.of("Asia/Kolkata")).minusMonths(1);
2019-05
Since the new month doesn’t begin at the same point in time in all time zones, I recommend that you state your desired time zone as shown.
Only then find the last day of the month:
LocalDate lastDayOfLastMonth = lastMonth.atEndOfMonth();
2019-05-31
Avoid Date and Calendar
I recommend you don’t use Date and Calendar. Those classes are poorly designed and long outdated. Instead use LocalDate and other classes from java.time, the modern Java date and time API. This will also save you from the external dependency on Apache DateUtils since its functionality is generally built into the modern classes.
Links
Documentation of org.apache.commons.lang3.time.DateUtils.addMonths
Oracle tutorial: Date Time explaining how to use java.time.

Java 8 substract dates but keep the hour

I want to subtract 7 days from Now, but keeping the time, so If now is
12/09/2018 at 18:30, get 05/09/2018 at 18:30...
I've tried:
public static Date subtractDays (int numDaysToSubstract) {
LocalDate now = LocalDate.now().minusDays(numDaysToSubstract);
return Date.from(now.atStartOfDay(ZoneId.systemDefault()).toInstant());
}
But I got 05/09/2018 at 00:00
As others have suggested, LocalDate and atStartOfDay should have been red flags based on just their name. They are the wrong type to describe a time and the wrong method to maintain the time.
It's also kind of pointless to go through LocalDateTime to then convert it to an Instant. Just use an Instant straight up
public static Date subtractDays(int numDaysToSubstract) {
return Date.from(Instant.now().minus(numDaysToSubstract, ChronoUnit.DAYS));
// or
// return Date.from(Instant.now().minus(Duration.ofDays(numDaysToSubstract)));
}
(I assume you're using java.util.Date because of compatibility with some old API.)
It’s unclear from the code in the other answers posted until now how they handle summer time (DST) and other time anomalies. And they do that differently. To make it clearer that you want 18.30 last week if time now is 18.30, no matter if a transition to or from summer time has happened in the meantime I suggest using ZonedDateTime:
System.out.println("Now: " + Instant.now());
Instant aWeekAgo = ZonedDateTime.now(ZoneId.of("Europe/Madrid"))
.minusWeeks(1)
.toInstant();
System.out.println("A week ago in Spain: " + aWeekAgo);
Since summer time in Spain hasn’t ended or begun within the last week, running the code snippet just now gave the same time of day also in UTC (which is what Instant prints):
Now: 2018-09-13T09:46:58.066957Z
A week ago in Spain: 2018-09-06T09:46:58.102680Z
I trust you to adapt the idea to your code.
Use class LocalDateTime instead of LocalDate (which doesn't contain a time component..)
You should use LocalDateTime instead of LocalDate
LocalDate is just a description of the date without time or time-zone
public static Date subtractDays (int numDaysToSubstract) {
LocalDateTime now = LocalDateTime.now().minusDays(numDaysToSubstract);
return Date.from(now.atZone(ZoneId.systemDefault()).toInstant());
}
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class Test {
public static String subtractDays (int numDaysToSubstract) {
LocalDateTime now = LocalDateTime.now().minusDays(numDaysToSubstract);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatDateTime = now.format(formatter);
return formatDateTime;
}
public static void main(String[] args){
System.out.println(subtractDays(7));
}
}

Categories

Resources