Store a local year for Date - java

I am going to store only year value in Database and retrieve it.
This is my domain (POJO)
#Entity
public class Publisher {
public Publisher(..., Date establishDate) {
//assign other variables
this.setEstablishDate(establishDate);
}
#NotNull
private Date establishDate;
...
}
And here is my DTO:
#NotNull
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy")
private Long establish_date;
Here, i am creating a new publisher:
new Publisher(..., new Date(this.establish_date));
I sent a json with value 1370 for establish_date (for post a new publisher) , but in Database it displays as: 1970-01-01 03:30:01
Why?
And when i Get the Publisher, it displays establish_date as 1000 !
What is wrong ?

You are using the wrong constructor. The argument specifies the milliseconds since 1970 - not a year: Date(long) You may use the right constructor: Date(int, int, int)
Note that most of the Date API is deprecated. There are better alternatives like Calendar and DateTime. Since you are only storing the year you could also use plain integer. This will make a lot easier.

Related

java.time.format.DateTimeParseException: Text '03/03/2020,03/03/2020' could not be parsed, unparsed text found at index 10

I have one form which contains "NO" and "Date". It will be Dynamic form. While doing a batch update in Spring Boot JPA i got the "java.time.format.DateTimeParseException: Text '03/03/2020,03/03/2020' could not be parsed, unparsed text found at index 10" exception
#RequestMapping(value="/abcpage", produces = { MediaType.APPLICATION_JSON_VALUE })
public String savePurchaseEntries(#ModelAttribute ABC abc,HttpSession session)
{
System.out.println(abc);
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
LocalDate today = LocalDate.parse(abc.getDate(),dateTimeFormatter);
abc.setLoclaDate(today);
return "redirect:/home";
}
Here ABC is the entity class and i can get the date value in dd/mm/yyyy format and convert into localdate and set into the entity.
ABC[NO=101,102,date=03/03/2020,03/03/2020]
for one entry it is working fine but while batch it throw the exception.
#Entity
class ABC{
#column(name="NO")
private String NO;
#Transient
private String date;
#Column(name="invdate")
private LocalDate loclaDate;
//getters & setters//tostring
}
I think problem with your code, if I understood your input correctly, is that you're passing comma(,) separated date strings in LocalDate.parse(abc.getDate(),dateTimeFormatter).
You need to pass a single date each time to parse() method as it tries to format the provided string input with that of date formatter format and hence error occurs when it encounters comma(,) in input of "03/03/2020,03/03/2020".
Please refer to official documentation for same.
Below is something you can try :
String[] inputDates = abc.getDate().split[","];
for (String date : inputDates) {
// you can now use LocalDate.parse(abc.getDate(),dateTimeFormatter) here
// write your logic here.
}
I hope this helps you get your doubt cleared, if not let me know your exact question and I will try to help you out.
EDIT 1 For inserting data
Below is a way in which you can insert data,
Create a table which will store dates having 3 columns - id(P.K.), abc_id(F.K. ref. of ABC table), date (store single date here).
Now let's say name of above table is abc_date_map, then reference this entity as OneToMany in your ABC entity. Like below,
#Entity
class ABC {
#Column(name="NO")
private String NO;
#Transient
private String date;
#Column(name="abc_date_map_id")
private List<AbcDateMap> abcDateMapEntityList;
//getters & setters//tostring
}
And your AbcDateMap entity will be like
#Entity
public class AbcDateMap{
#Column(name="abc_id")
private Integer abcId;
#Column(name="date")
private LocalDate localDate;
// getters setters
}
And your entity insertion logic will be like :
public Long insert(ABC abc) {
abc.setNo(/*something*/);
List<AbcDateMap> l = new ArrayList<>();
AbcDateMap abcDate = new AbcDateMap();
for (String date : abc.getDate().split(",")) {
abcDate.setLocalDate(/*parse date here and store*/);
abcDate.setAbcId(abc.getId());
}
abc.setAbcDateMapEntityList(l);
repo.save(abc);
}
Now above is not exact code, you will have to polish it out, might have syntax/semantics mistakes. Also you will need to change it according to your requirements.

convert xmlGregorianCalendar to Date and reverse

i all, i have a spring boot application. what i want in specific is to convert a class (that have nestet object field) in his corrispective entity. example:
public class example{
String string;
ObjectExample object;
}
public class ObjectExample{
String oneString;
XMLGregorianCalendar date;
}
this 2 object are also marked in another package as entities, but ovviusly in the ObjectExampleEntity i have Date date instead XMLGregorianCalendar, like this with the example
#Entity
public class example{
String string;
ObjectExample object;
}
#Entity
public class ObjectExample{
String oneString;
Date date;
}
because i have a big model and big entity (this above is only an example) with a lot of nested classes , i use dozer to convert from the model to the class.
consider for example that the repository jpa is only created for the father example class.
i want to know how i can with dozer convert from Date (entity) to XMLGregorianCalendar (model) and reverse. the model and the entity,i repeat are equal. the only difference is the type of the date. thanks
I am assuming:
Since your variable is named date it contains a calendar date (without time of day).
You are tied to XMLGregorianCalendar because of a WSDL outside your control, but you can change type on the entity side.
Based on these assumptions I recommend LocalDate on the entity side. It’s part of java.time, the modern Java date and time API, and represents exactly a date without time of day. The Date class that you used is poorly designed, long outdated and not recommended. Also despite the name a Date never represented a date, but a point in time.
There are more options. I am presenting three.
Option 1: transfer individual fields
From XMLGregorianCalendar to LocalDate:
DatatypeFactory xmlFactory = DatatypeFactory.newInstance();
XMLGregorianCalendar wsDate = xmlFactory
.newXMLGregorianCalendarDate(2019, DatatypeConstants.MARCH, 30,
DatatypeConstants.FIELD_UNDEFINED);
// Validate
if ((wsDate.getHour() != 0 && wsDate.getHour() != DatatypeConstants.FIELD_UNDEFINED)
|| (wsDate.getMinute() != 0 && wsDate.getMinute() != DatatypeConstants.FIELD_UNDEFINED)
|| (wsDate.getSecond() != 0 && wsDate.getSecond() != DatatypeConstants.FIELD_UNDEFINED)
|| (wsDate.getMillisecond() != 0 && wsDate.getMillisecond() != DatatypeConstants.FIELD_UNDEFINED)) {
System.out.println("Warning: time of day will be lost in conversion");
}
if (wsDate.getTimezone() != DatatypeConstants.FIELD_UNDEFINED) {
System.out.println("Warning: UTC offset will be lost in conversion");
}
// Convert
LocalDate entityDate = LocalDate.of(wsDate.getYear(), wsDate.getMonth(), wsDate.getDay());
System.out.println(entityDate);
The output is in this case:
2019-03-30
From LocalDate to XMLGregorianCalendar:
LocalDate entityDate = LocalDate.of(2019, Month.MARCH, 31);
XMLGregorianCalendar wsDate = xmlFactory.newXMLGregorianCalendarDate(
entityDate.getYear(),
entityDate.getMonthValue(),
entityDate.getDayOfMonth(),
DatatypeConstants.FIELD_UNDEFINED);
System.out.println(wsDate);
2019-03-31
Advantage of this way: It’s pretty straightforward. Disadvantage: You and your reader need to take care that the fields are mentioned in the right order.
Option 2: convert via strings
// Validate as before
// Convert
LocalDate entityDate = LocalDate.parse(wsDate.toXMLFormat());
Result is as before.
XMLGregorianCalendar wsDate
= xmlFactory.newXMLGregorianCalendar(entityDate.toString());
Advantage: it’s brief, and there’s no surprise that the results are correct. Disadvantage: To me it feels like a waste to format into a string only to parse it back.
Option 3: convert via GregorianCalendar and ZonedDateTime
ZonedDateTime zdt = wsDate.toGregorianCalendar().toZonedDateTime();
// Validate
if (! zdt.toLocalTime().equals(LocalTime.MIN)) {
System.out.println("Warning: time of day will be lost in conversion");
}
if (! zdt.getZone().equals(ZoneId.systemDefault())) {
System.out.println("Warning: UTC offset will be lost in conversion");
}
// Finish conversion
LocalDate entityDate = zdt.toLocalDate();
And the other way:
// It doesn’t matter which time zone we pick
// since we are discarding it after conversion anyway
ZonedDateTime zdt = entityDate.atStartOfDay(ZoneOffset.UTC);
GregorianCalendar gCal = GregorianCalendar.from(zdt);
XMLGregorianCalendar wsDate = xmlFactory.newXMLGregorianCalendar(gCal);
wsDate.setTime(DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED,
DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED);
wsDate.setTimezone(DatatypeConstants.FIELD_UNDEFINED);
The validation I present here is a bit simpler but also not quite so strict. If you want strict validation, you can just use the validation from before.
Advantages: I think it’s the official way; at least it uses the conversion methods offered. What I like is that the conversion itself is direct and brief. Disadvantage: When converting to XMLGregorianCalendar we need to set the unused fields to undefined manually, which makes it wordy.
Conclusion
I have presented three options each with their pros and cons. You may also mix, of course, but using a similar conversion both ways is probably less confusing in the end.

JPA set timestamp generated by database but not CURRENTTIME or UPDATETIME

I have a class like this
#Entity
#Table(name = "Event")
public class Event {
#Transient
public static final long MAX_TIMESTAMP = 253402214400000L; // 9999-12-31 00:00:00
private Date creationTime;
private Date expiryTime;
private String otherValue;
public Event(int timeout, String otherValue){
this.creationTime = new Date();
this.expiryTime = (timeout == 0 ? new Date(MAX_TIMESTAMP) : new Date(creationTime.getTime() + SECONDS.toMillis(timeout)));
this.otherValue = otherValue;
}
}
I call save() methed in CrudRepository and save this data.
and I have a ScheduledExecutorService to find out some timeout events:
#Query("SELECT t FROM Event t WHERE t.expiryTime < CURRENT_TIMESTAMP")
List<Event> findTimeoutEvents();
this CURRENT_TIMESTAMP is database's time, but expiryTime is not. It means that I must make their time is same.sometimes, the application and database are not in the same machine, I can not make sure their time is same.
Can I set "expiryTime" generated by database? How can I pass the parameter "timeout" to database.
the database maybe postgresql or mysql.
thank you very much.
First of all I am not sure your code works, since instance of java.util.Date (if expiry time is java.util.Date object) can not be compared to int 0.
As for generating an expiryTime, yes, you obviously can. Check out how do triggers work.
Also I would like to add, that if you use spring-boot-starter-data-jpa, you may annotate creationTime field with #CreationTimestamp annotation. But I would personally set default value to CURRENT_TIMESTAMP() on db side.

Sending certificate with future timestamp

Suppose two people run the same code and the first one creates a certificate with createDate and expireDate and a file is valid if
createDate < currentTimeOfTheUserComputer < expireDate .
Now if the first person sends this certificate(suppose for him it is valid) to someone else who is 8 hours behind around the world ,for the second person it will be invalid.In such a scenario how is this problem resolved or is there a policy how it should be if we want the second person to be able to use it without waiting 8 hours?
RFC 5280, which handles X.509 certificates specifies two methods to encode validity times in certificates:
UTCTime
GeneralizedTime
Both rely on the GMT zone as reference. If both implementations use the correct time zone for generation and checking, your scenario should not present a problem.
See RFC 5280 on validity
EDIT: Sorry, I didn't realize that Date always uses UTC Time. So any time you want to get the date, you access it like this:
import java.util.Date;
public class CurrentDateTime {
public static String getCurrDateTime() {
Date date = new Date();
return date;
}
}
public class DateCertificate {
public static void createCertificate() {
Date createDate = CurrentDateTime.getCurrDateTime();
/* Save createDate to file or something */
}
public static boolean certificateValid() {
Date currentDate = CurrentDateTime.getCurrDateTime();
/* Get createDate and expireDate from file or something */
return currentDate.after(createDate) && currentDate.before(expireDate);
}
}
You can use getCurrDateTime() and some other Date methods to get the createDate and expireDate and save them to a file or however you want to store them, then use the certificateValid() method to check if the currentDate is between the two.
Thanks Jim for pointing out my mistake.
Note: This could be easily spoofed/tricked because it is dependent on the time reading from the client machine that is given to the JVM. So do not use this for free trial validation or the like.

What is the correct way to deal with fields in Kotlin?

How should I handle the migration from a Java class with fields to Kotlin properly?
A couple of reading into Kotlin's docs reveal that their classes can't have fields defined within them. Being the rebel that I am, actually trying to convert my existing Java code to its Kotlin counterpart (using Android Studio's Java to Kotlin converter feature) also marks "fields" with an unpleasantly blinding highlight.
This is my Java class:
public final class PaperDay implements Day {
private Date date;
private Weather weather;
PaperDay() {
// Obligatory empty ctor for Paper.
}
PaperDay(Date date) {
this.date = truncateTimeFromDate(date);
this.weather = Weather.SUNNY; // Default to SUNNY, 'cos sunny is good!
}
PaperDay(Date date, Weather weather) {
this.date = truncateTimeFromDate(date);
this.weather = weather;
}
private Date truncateTimeFromDate(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
...
..and this is what it looks like converted into a .kt:
How can I do this the Kotlin way?
I'm assuming you want something like this:
class PaperDay (private var date: Date,
private var weather: Weather = Weather.SUNNY) : Day {
init {
this.date = truncate(date)
}
private fun truncateTimeFromDate(date1: Date): Date {
return date1
}
}
You should try to use optional parameters (var weather: Weather = Weather.SUNNY) wherever you can, since it increases readability a lot.
To avoid the (somewhat ugly) init block you can also pass only one of the two properties as a constructor parameter (thanks to Jayson Minard), and calculate the other property in it's declaration by using a "normal" paramter:
class PaperDay (dateWithTime: Date,
private val weather: Weather = Weather.SUNNY): Day {
private val date: Date = truncateTimeFromDate(dateWithTime)
...
}
Note that this is also using val instead of var since immutability is usually the better option.
If you need to have the empty constructor as well, you can add this (although I don't think it's a good practice and it's an indicator for "bad"
design:
constructor() : this(Date())
Alternatively, adding a default value for all parameters in the constructor will implicitly create an empty constructor as well.
if you really want the nullability define your properties using ?. E.g.:
class PaperDay (private var date: Date?, private var weather: Weather? = Weather.SUNNY)
you can then also change the other constructor to constructor() : this(null)
Additionally, it's IMHO also a good idea to add the truncate... method as an extension function for the Date class instead of heaving it in this class:
fun Date.truncateTimeFromDate() {
Calendar calendar = Calendar.getInstance()
calendar.setTime(this)
calendar.set(Calendar.HOUR_OF_DAY, 0)
calendar.set(Calendar.MINUTE, 0)
...
}
Similar to #Lovis but avoiding the use of var which should be a "last resort":
class PaperDay (dateWithTime: Date = Date(), private val weather: Weather = Weather.SUNNY): Day {
private val date: Date = truncateTimeFromDate(dateWithTime)
private fun truncateTimeFromDate(dateWithTime : Date) : Date {
...
}
}
In this version, the constructor has one parameter that is not a class property, and the other is a property. Later in the class body, the property is declared and set to the truncated date.
If you have a default value for each constructor parameter, Kotlin will automatically create a default constructor that uses those defaults. No need to add it separately.
If your framework must instantiate with default constructor and then set the values after the fact, you'll want to do something more like the following and go back to using var:
class PaperDay (dateWithTime: Date = Date(), private var weather: Weather = Weather.SUNNY): Day {
private var date: Date = truncateTimeFromDate(dateWithTime)
set(value) { field = truncateTimeFromDate(value) }
private fun truncateTimeFromDate(dateWithTime : Date) : Date {
return dateWithTime
}
}
Now we have ensured we never have a invalid date being stored in the property by having a custom setter.
If you want interoperability for all variations of the constructor available from Java, you can use the #JvmOverloads annotation on the constructor to generate other permutations of using default parameter values.
And as #Lovis points out, move the truncateTimeFromDate to an extension function on the Date class. It can be local to the file, to the module, to the class, and in all those cases it will read better.

Categories