Modify date without modifying time - java

With JodaTime, without using the 'plus' or 'minus' functions and using the least lines of code, how can I set a new date without modifying the time?
My first attempt was to store the 'time' parts of the DateTime in separate ints using getHoursOfDay() and getMinutesOfHour() etc - then create a new DateTime with the required date and set the hours, minutes, and seconds back again. But this method is pretty clunky, and I was wondering if there was a less verbose method for doing this - ideally with just one line of code.
For example:
22/05/2013 13:40:02 >>>> 30/08/2014 13:40:02

Is JodaTime a must? Basic way to do this is
1. extract just time from timestamp.
2. add this to just date
long timestamp = System.currentTimeMillis(); //OK we have some timestamp
long justTime = timestamp % 1000 * 60 * 60 * 24;// just tiem contains just time part
long newTimestamp = getDateFromSomeSource();//now we have date from some source
justNewDate = newTimestamp - (newTimestamp % 1000 * 60 * 60 * 24);//extract just date
result = justNewDate + justTime;
Something like this.

Previously accepted answer were removed by moderator, as it contains only link to javadoc.
Here is edited version.
You could do it like this
DateTime myDate = ...
myDate.withDate(desiredYear, desiredMonth, desiredDayOfMonth);
JavaDoc is here: DateTime.withDate(int year, int month, int dayOfMonth)

use withFields like this:
new DateTime().withFields(new LocalDate(2000,1,1))
This will set all date time fields of the DateTime to those that are contained in the LocalDate - year, month and day in this case. This will work with any ReadablePartial implementation like YearMonth for example.

Related

Apache POI Excel Date

I'm trying to do automations in Java with Apache POI and I need to convert a date dd-MM-yyyy into the format that Excel saves dates. like 31.12.2022 equals to 44926 in Excel. so I searched a bit and discovered that the number equals the days that have passed between 1.1.1900 and in this example 31.12.2022 so i searched for a function that calculates this but only got some that have irregular differences than from excel. I also tried with ChatGPT but no luck.
Date date1 = new Date(year, month, day);// some date
Date date2 = new Date(1900,1,1); // some other date
long difference = date1.getTime() - date2.getTime();
int differenceDays = (int) (difference / (1000 * 60 * 60 * 24));
return differenceDays;
I used this code and as I said earlier it'ss not the same result I get in Excel at first I thought it was just a difference of 4 that is always the same so I just added +4 but then I realized that this doesnt work because sometimes its 3 or smth else.

Different results with LocalDateTime by different calls with same parameter

The problem is, that I have to change my code from Calendar object to LocalDateTime object. But I don't get the same timestamp at the end. In the first call I got the same with localDateTime, on the next calls I get other timestamps and I use the same parameter to calculate the timestamps. I don't know why I get different results. It isn't logic for me. What I want to do is: I get a UTC Timestamp. I want to set it on german(Europe/Berlin) time(important about summer and winter season). Then I want to calculate the start of the day(00:00) and the end of the day(23:59). Then I want to get the timestamp for this times.
I build an API with spring-boot. The above described function is invoked by a controller class from spring-boot. The first call after the start of the API calculates the expected results. But all next calls give other results. Always with 7200 difference. I tried other ways with localDateTime, but it never gaves the same timestamp as with calendar.
LocalDateTimeWay:
LocalDateTime localDateTime =
LocalDateTime.ofInstant(Instant.ofEpochSecond(timestamp), ZoneId.systemDefault());
LocalDateTime dayStartLocal = localDateTime.withHour(0)
.withMinute(0)
.withSecond(0)
.withNano(0);
ZonedDateTime startZonedDateTime = dayStartLocal.atZone(ZoneId.systemDefault());
long dayStartTimeStamp = startZonedDateTime.toInstant().getEpochSecond();
LocalDateTime dayEndLocal = localDateTime.withHour(23)
.withMinute(59)
.withSecond(59)
.withNano(999);
ZonedDateTime endZonedDateTime = dayEndLocal.atZone(ZoneId.systemDefault());
long dayEndTimeStamp = endZonedDateTime.toInstant().getEpochSecond();
CalendarWay:
Calendar cal=Calendar.getInstance();
cal.setTimeInMillis(timestamp*1000);
cal.setTimeZone(TimeZone.getTimeZone("Europe/Berlin"));
cal.set(Calendar.HOUR_OF_DAY,0);
cal.set(Calendar.MINUTE,0);
cal.set(Calendar.SECOND,0);
cal.set(Calendar.MILLISECOND,0);
long dayStartTimeStamp = calendar.getTimeInMillis()/1000L;
cal.set(Calendar.HOUR_OF_DAY,23);
cal.set(Calendar.MINUTE,59);
cal.set(Calendar.SECOND,59);
cal.set(Calendar.MILLISECOND,999);
long dayEndTimeStamp = calendar.getTimeInMillis()/1000L;
I want by the param timestamp 1536933600. The result 1536876000 and 1536962399. But I get after the first request by localDateTime method 1536883200 and 1536969599.
You are using system default zone for your java.time code and Europe/Berlin zone for Calendar code. The 7200 is most likely the difference between your system time zone and Europe/Berlin (2 hours).
Replace all ZoneId.systemDefault() with ZoneId.of("Europe/Berlin") and you will get the same values in both versions:
timestamp = 1536933600
dayStartTimeStamp = 1536876000
dayEndTimeStamp = 1536962399

Java XMLGregorianCalendar format

I am currently stuck with XMLGregorianCalendar formatting problem and would like to seek help from you java gurus. With a function call from other system, I got a data object displayed on web page with "SUBMIT_DATE":1516032000000 and "SUBMIT_TIME":36895000 (both with returned type XMLGregorianCalendar). How can I know the correct human readable date and time in this case?
Thank you for your time and help.
Update after clarification
// We first need to check that the fields we need are defined
if (submitDate.getTimezone() == DatatypeConstants.FIELD_UNDEFINED) {
throw new IllegalStateException("No time zone defined in submit date " + submitDate);
}
if (submitDate.getYear() == DatatypeConstants.FIELD_UNDEFINED
|| submitDate.getMonth() == DatatypeConstants.FIELD_UNDEFINED
|| submitDate.getDay() == DatatypeConstants.FIELD_UNDEFINED) {
throw new IllegalStateException("Date not defined in submit date " + submitDate);
}
if (submitTime.getHour() == DatatypeConstants.FIELD_UNDEFINED
|| submitTime.getMinute() == DatatypeConstants.FIELD_UNDEFINED
|| submitTime.getSecond() == DatatypeConstants.FIELD_UNDEFINED) {
throw new IllegalStateException("Time of day not defined in submit time " + submitTime);
}
if (submitTime.getTimezone() != DatatypeConstants.FIELD_UNDEFINED
&& submitTime.getTimezone() != submitDate.getTimezone()) {
throw new IllegalStateException("Conflicting offsets " + submitDate.getTimezone()
+ " and " + submitTime.getTimezone() + " minutes");
}
// then format into a human readable string
final ZoneId userZone = ZoneId.of("Asia/Taipei");
final Locale userLocale = Locale.forLanguageTag("zh-TW");
DateTimeFormatter localizedFormatter = DateTimeFormatter
.ofLocalizedDateTime(FormatStyle.LONG)
.withLocale(userLocale);
ZonedDateTime dateTime = submitDate.toGregorianCalendar()
.toZonedDateTime()
.with(LocalTime.of(submitTime.getHour(), submitTime.getMinute(), submitTime.getSecond()))
.withZoneSameInstant(userZone);
String humanReadableDateTime = dateTime.format(localizedFormatter);
System.out.println(humanReadableDateTime);
This prints:
2018年1月16日 上午10時14分55秒
I am assuming that submitDate and submitTime are XMLGregorianCalendar objects that you have got from the complex object that you have received from a remote system. I am further assuming that you can require the date to contain a UTC offset. Though the method is called getTimezone, what it really returns is not a time zone, but an offset in minutes from UTC (or GMT). The extensive checks in the four if statements are necessary because XMLGregorianCalendar is very flexible with which fields are defined and which not.
To display the date and time in a format suitable for a user audience, you need to know that audience’s time zone and locale. Once you know those, please fill them in in the above snippet. If you trust the JVM’s settings, you may use ZoneId.systemDefault() and/or Locale.getDefault(Locale.Category.FORMAT) You may also choose between format styles FULL, LONG, MEDIUM and SHORT.
If you don’t receive an offset, you will need to rely on the date and time already being at the user’s offset. On one hand it’s simpler, on the other hand it is more fragile since if the date and time are given at another offset than the user expects, s/he will receive incorrect information, which is worse than receiving no information at all. First check that there is indeed no offset:
if (submitDate.getTimezone() != DatatypeConstants.FIELD_UNDEFINED
|| submitTime.getTimezone() != DatatypeConstants.FIELD_UNDEFINED) {
throw new IllegalStateException("Unexpected offset");
}
Also check that required fields are defined, this is the same as before. Then create a LocalDateTime object and format it:
LocalDateTime dateTime = LocalDateTime.of(
submitDate.getYear(), submitDate.getMonth(), submitDate.getDay(),
submitTime.getHour(), submitTime.getMinute(), submitTime.getSecond());
String humanReadableDateTime = dateTime.format(localizedFormatter);
I got the same result as above.
Original answer
final ZoneId userZone = ZoneId.of("Asia/Taipei");
final Locale userLocale = Locale.forLanguageTag("zh-TW");
ZonedDateTime submitDateTime
= Instant.ofEpochMilli(submitDate + submitTime).atZone(userZone);
DateTimeFormatter localizedFormatter = DateTimeFormatter
.ofLocalizedDateTime(FormatStyle.LONG)
.withLocale(userLocale);
String humanReadableDateTime = submitDateTime.format(localizedFormatter);
System.out.println(humanReadableDateTime);
This prints
2018年1月16日 上午10時14分55秒
To display the date and time in a format suitable for a user audience, you need to know that audience’s time zone and locale. Once you know those, please fill them in in the first two lines of the above snippet. If you trust the computer’s settings, you may use ZoneId.systemDefault() and/or Locale.getDefault(Locale.Category.FORMAT) You may also choose between format styles FULL, LONG, MEDIUM and SHORT. For this purpose I think you can ignore the information that the returned type is XMLGregorianCalendar.
As #user unknown in another answer I am assuming that you can just add the two numeric values. The first almost certainly denotes milliseconds since the epoch, the sum probably too. So why were they passed as two values and not just one? My best guess is that they pass the date separately for any client that just needs the date and not the time of day. The date value falls at midnight in time zones at offset +08:00, this would agree with China, Philippines, Malaysia and a dozen other time zones.
If instead of the numbers you have got two XMLGregorianCalendar objects, getting the date and time is a different story, but you may still use the same way of formatting them.
final GregorianCalendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(date);
return DatatypeFactory.newInstance().newXMLGregorianCalendar(
calendar);
This should work..
Pass your millisecs
Your inputs look like they're just the date without time in milliseconds and the time without date in milliseconds.
If you divide both values by 1000:
date -d #1516032000
Mo 15. Jan 17:00:00 CET 2018
date -d #36895
Do 1. Jan 11:14:55 CET 1970
Well - but why 17:00:00? Maybe a time zone issue.
Here is the aggregate:
date -d #$((1516032000+36895))
Di 16. Jan 03:14:55 CET 2018
The various date/time formats for Java have methods, which take a long parameter for seconds since epoch (1.1.1970) to set the time.

java.sql.timestamp versus date

I am using Derby database with Java and Eclipse. I have a table which has a TIMESTAMP field and I use a model to populate a JTable from it. I am finding timestamp and data and java.sql and java.utils very confusing. The following line of code errors with cannot cast date to timestamp. mod is the model interfacing Derby table and JTable.
int rowcount = mod.getRowCount();
java.sql.Timestamp ts = (java.sql.Timestamp) mod.getValueAt(rowcount-1,1);
My objective is to get the date of the most recent record and subtract 30 days then run an sql query on the same database to find all the records more recent than that date. How do I recover the first timestamp, subtract the 30 days, then construct a query with the result of the subtraction as the condition in a WHERE clause. Sounds simple but I am having such difficulty that I feel I must be missing some fundamental principal. I thought conversion to long and back again might be the route but came up against the same cast problem.
Timestamp is declared as
public class Timestamp extends java.util.Date { ... }
Therefore you can't cast date to timstamp, you could create a timestamp from a date.
Timstamp ts = new Timestamp( date.getTime() );
To subtract 30 days this sequence might be helpful:
Calendar cal = new GregorianCalendar();
cal.setTime( date.getTime() );
cal.add( Calendar.DAY_OF_MONTH, -30 );
Date d30 = cal.getTime();
Anyway I would try to perform this using only SQL.

java.util.Calendar not reporting the correct timeInMillis

findCalendarStart: time into Calendar: 1260575897
findCalendarStart: set hour : 13
findCalendarStart: after hour : 1249775897
findCalendarStart: after hour string: Thu Jan 15 11:09:35 UTC 1970
findCalendarStart: set minutes : 13
findCalendarStart: after minutes: 1250015897
findCalendarStart: what calendar returns: 1250015897
I place a Date (initialized by passing long from a millisecond from today) in a Calendar. Calendar is correctly initialized. In the first calculation, I change the hour of day to 13. At this point, startCalTime.set(Calendar.HOUR_OF_DAY, ((new Integer(m.group(1)).intValue())*2)-1 );
I am passing the right hour of day values and minutes because Im seeing them in the logger. What could possibly be causing calendar to come up with such strange dates after I only change the hour of day from todays Date object?
More code:
Calendar startCalTime = Calendar.getInstance(TimeZone.getTimeZone("America/Los_Angeles"));
Date d = new Date(creationTime);
startCalTime.setTime(d);
startCalTime.getTimeInMillis();
..regex..
if(m.find()){
//SET HOUR OF DAY
_logger.warning("set hour 1 : " + new Integer((new Integer(m.group(1)).intValue())-1)); startCalTime.set(Calendar.HOUR_OF_DAY, new Integer(m.group(1)).intValue()-1 );
_logger.warning("after hour 1: " + new Long(startCalTime.getTime().getTime()));
_logger.warning("after hour 1 string: " + startCalTime.getTime().toString());
//SET MINUTE
_logger.warning("set minutes 1 : " + new Integer(m.group(2).toString()));
startCalTime.set(Calendar.MINUTE, new Integer(m.group(2)).intValue());
_logger.warning("after minutes 1: " + new Long(startCalTime.getTime().getTime()));}
Thanks,
culov
Let's see how you initialize your date. I suspect that instead of milliseconds, you are passing it seconds since epoch start - this (seconds, not milliseconds) is how regular Unix timestamps are defined. Java uses milliseconds for better granularity.
Calendar startCalTime = Calendar.getInstance(TimeZone.getTimeZone("America/Los_Angeles"));
Date d = new Date(creationTime);
What happens there? startCalTime and creationTime don't seem to be connected, I'd assume they should be?
Also for very slightly better performance/memory footprint, avoid new Integer/Long as much as possible and use Long/Integer.valueOf() instead.
Those times in your Calendar don't look right. If those are supposed to be times in milliseconds, then 126..... represents a time of only 350 hours, which looks to be off by almost 40 years.
The reason seems to be that your initialization is not really setting your calendar to today's date. The initial date seems to be just a few hours past the epoch.
Please post some more code and we can fix it for you.

Categories