Why does GregorianCalendar set method give slightly and inconsistent wrong times? - java

In NetBeans, I run the code below.
The output from one run is
Intended time = 1970-0-1 0:0:0.000
GC time in ms = 102
Reformated GC time = 1970-01-01 00:00:00.102
Deprecated Date ms = 0
Deprecated time = 1970-01-01 00:00:00.000
The output from another run is
Intended time = 1970-0-1 0:0:0.000
GC time in ms = 575
Reformated GC time = 1970-01-01 00:00:00.575
Deprecated Date ms = 0
Deprecated time = 1970-01-01 00:00:00.000
Q1: Why is the Reformatted time (from GregorianCalendar set(...) method) have extra milliseconds - Deprecated - using new Date(...) does not!
Q2: Why does the number of ms vary from run to run?
public class TestGregorianCalendar {
public static void main(String[] args){
String timeZoneString = "GMT+00";
GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone(timeZoneString));
int year = 1970;
int month = 0; // Jan
int day = 1;
int hour = 0;
int min = 0;
int sec = 0;
calendar.set(year, month, day, hour, min, sec);
long ms;
Date date;
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
df.setTimeZone(TimeZone.getTimeZone(timeZoneString));
System.out.println("Intended time = "+year+"-"+month+"-"+day
+" "+hour+":"+min+":"+sec+".000");
calendar.set(year, month, day, hour, min, sec);
ms = calendar.getTimeInMillis();
System.out.println("GC time in ms = "+Long.toString(ms));
date = new Date(ms);
System.out.println("Reformated GC time = "+df.format(date));
Date deprecatedDate = new Date(year-1900, month, day, hour+1, min, sec);
System.out.println("Deprecated Date ms = "+Long.toString(deprecatedDate.getTime()));
System.out.println("Deprecated time = "+df.format(deprecatedDate));
}
}
Grateful for insight!

java.time
I recommend that you use java.time, the modern Java date and time API, for your date and time work.
OffsetDateTime dateTime = OffsetDateTime.of(1970, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC);
System.out.println(dateTime);
long ms = dateTime.toInstant().toEpochMilli();
System.out.println(ms);
Output:
1970-01-01T00:00Z
0
There are no extra milliseconds, or they would gave been printed twice, once in each of the output lines. java.time sanely numbers months the same way humans do, so I have given January as 1. The last 0 in the argument list to OffsetDateTIme.of() is nanosecond of second and ensures that the fraction of second will be 0.
If you want formatted output:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS");
System.out.println(dateTime.format(formatter));
1970-01-01 00:00:00.000
What went wrong in your code?
Mark Rotteveel already in the comment has answered both of your questions. new GregorianCalendar(TimeZone.getTimeZone(timeZoneString)) created a GregorianCalendar representing the current moment in the specified time zone, with millisecond precision. calendar.set(year, month, day, hour, min, sec) sets the mentioned fields to those values. It does not change other fields such as era and millisecond (of second). So the millisecond value that you get reflects the time of the second the GregorianCalendar object was created, which obviously is not the same each time. This explains the apparently random variations. This is just one of very many confusing sides of GregorianCalendar. I recommend that you don’t use that class.
new Date(year-1900, month, day, hour+1, min, sec) — whoa, using the constructor that has been deprecated since February 1997 because it works unreliably across time zones — creates a new Date object from those values alone without looking at the clock, so here the millisecond of second is 0.
Link
Oracle tutorial: Date Time explaining how to use java.time.

Instant.EPOCH
Instant.EPOCH is the constant for the 1970-01-01T00:00:00Z epoch instant.
import java.time.Instant;
public class Main {
public static void main(String[] args) {
Instant instant = Instant.EPOCH;
System.out.println(instant);
}
}
Output:
1970-01-01T00:00:00Z
In case you need a date-time string representing the instant into a different pattern, you can convert it into OffsetDateTime using Instant#atOffset and then format the same using a DateTimeFormatter instantiated with the desired pattern.
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
Instant instant = Instant.EPOCH;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS");
String formatted = formatter.format(instant.atOffset(ZoneOffset.UTC));
System.out.println(formatted);
}
}
Output:
1970-01-01 00:00:00.000
The date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. I suggest you should stop using them completely and switch to the modern date-time API. Learn more about the modern date-time API at Trail: Date Time.

Related

Some dates cannot be converted correctly in Java to an epoch timestamps at the midnight of a specific timezone

This Java code, given a date as a string, is supposed to print the epoch timestamp for the same date at the midnight for the CET zone (supposing I'm not in the same zone).
public static void main(String[] args) throws ParseException {
String dateStr = "1995-06-06";
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
formatter.setTimeZone(TimeZone.getTimeZone("CET"));
Date date = formatter.parse(dateStr);
Calendar c = new GregorianCalendar();
c.setTimeZone(TimeZone.getTimeZone("CET"));
c.setTime(date);
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
System.out.println("Epoch timestamp = " + c.getTime().getTime());
}
If I run the above program I should get printed:
Epoch timestamp = 802389600000
And I can verify it's correct here:
https://www.epochconverter.com/timezones?q=802389600&tz=Europe%2FMalta
Now, that works for most of the dates. However, there are some bizarre dates like "1975-09-19", where it doesn't work. In fact, It generates 180313200000 as a timestamp, which gives 1am and not midnight:
https://www.epochconverter.com/timezones?q=180313200&tz=Europe%2FMalta
Can you explain why? What am I missing?
Time zone discrepancy
Your Java code uses CET, which is not really a time zone (for example because most of the areas where it’s used use CEST instead for most of the year). Java translates CET to Europe/Paris. France and Paris did not use summer time (DST) in 1975. It was reintroduced in March 1976.
Your link to the epoch converter specifies Malta time zone (Europe/Malta). Malta did use summer time in 1975: it was on CEST from 20 April to 21 September that year.
This explains the difference in your results.
In Java code
If you wanted Malta time:
String dateStr = "1975-09-19";
long epochTimestamp =
LocalDate
.parse(dateStr)
.atStartOfDay(ZoneId.of("Europe/Malta"))
.toInstant()
.toEpochMilli();
System.out.println("Epoch timestamp = " + epochTimestamp);
This prints:
Epoch timestamp = 180309600000
And the epoch converter that you linked to is happy to agree:
Conversion results (180309600)
180309600 converts to Friday September 19, 1975 00:00:00 (am) in
time zone Europe/Malta (CEST) The offset (difference to Greenwich
Time/GMT) is +02:00 or in seconds 7200. This date is in daylight
saving time.
In Java do use java.time, the modern Java date and time API, for your date and time work. It is so much nicer to work with compared to the old date and time classes like SimpleDateFormat, TimeZone, Date and Calendar. Also setting the hours, etc., to 0 is not the correct way to get the first moment of the day. There are cases where summer time begins at the start of the day, so the first moment of the day is 01:00:00. Java knows that, so the atStartOfDay method will give you the correct forst moment of the day in question.
And no matter if using outdated or modern classes always specify time zone in the region/city format, for example Europe/Paris or Europe/Malta. The three, four and five letter time zone abbreviations are often ambiguous and often not true time zones, so not to be relied on.
Links
Time Zone in Paris, Île-de-France, France
Time Zone in Valletta, Malta
Oracle tutorial: Date Time explaining how to use java.time.
There seems to be a difference concerning daylight saving time between your date examples.
If I use java.time (which should always be used since Java 8), I get results with different offsets:
"+02:00" for "1995-06-06" and
"+01:00" for "1975-09-19"
This is how I got the results:
public static void main(String[] args) {
// provide two sample dates
String workingDateStr = "1995-06-06";
String failingDateStr = "1975-09-19";
// and a formatter that parses the format
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
// then parse them to date objects that don't know about time or zone
LocalDate workingDate = LocalDate.parse(workingDateStr, dtf);
LocalDate failingDate = LocalDate.parse(failingDateStr, dtf);
/*
* then create an objects that are aware of time and zone
* by using the parsed dates, adding a time of 00:00:00 and a zone
*/
ZonedDateTime workingZdt = ZonedDateTime.of(workingDate, LocalTime.MIN, ZoneId.of("CET"));
ZonedDateTime failingZdt = ZonedDateTime.of(failingDate, LocalTime.MIN, ZoneId.of("CET"));
// finally, print different representations of the results
System.out.println(workingZdt + " ——> " + workingZdt.toInstant().toEpochMilli());
System.out.println(failingZdt + " ——> " + failingZdt.toInstant().toEpochMilli());
}
Output:
1995-06-06T00:00+02:00[CET] ——> 802389600000
1975-09-19T00:00+01:00[CET] ——> 180313200000
That means you might be better off using specific offsets instead of zones.
This issue could be due to the timing of the introduction of Daylight Saving Time in Malta, have a look at the following code and its output:
public static void main(String[] args) {
// provide two sample dates
String failingDateStr = "1975-09-19";
// and a formatter that parses the format
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
// then parse them to date objects that don't know about time or zone
LocalDate failingDate = LocalDate.parse(failingDateStr, dtf);
/*
* then create an objects that are aware of time and zone
* by using the parsed dates, adding a time of 00:00:00 and a zone
*/
ZonedDateTime failingZdt = ZonedDateTime.of(failingDate, LocalTime.MIN, ZoneId.of("CET"));
// add some years to 1975 and...
for (int year = 0; year < 4; year++) {
// ... print the different representations of the result
System.out.println(failingZdt.plusYears(year) + " ——> "
+ failingZdt.plusYears(year).toInstant().toEpochMilli());
}
}
Output:
1975-09-19T00:00+01:00[CET] ——> 180313200000
1976-09-19T00:00+01:00[CET] ——> 211935600000
1977-09-19T00:00+02:00[CET] ——> 243468000000
1978-09-19T00:00+02:00[CET] ——> 275004000000
This output indicates an introduction in 1977... Is that correct?

How to get the end of day as a OffsetDateTime in the format 2019-12-29 05:59:59.9999990 +00:00?

Supposing the time zone is CST. I have a webservice that returns a java.util.Date as "2020-03-14". I want to convert it to OffsetDateTime in the format "2020-03-14 05:59:59.9999990 +00:00". The below code does not have the time information.
Date endDate = someService.getEndDate();
Instant instant = Instant.ofEpochMilli(endDate.getTime());
OffsetDateTime offsetEndDt = OffsetDateTime.ofInstant(instant, ZoneOffset.UTC);
The value of offsetEndDt is 2020-03-14T05:00Z
An OffsetDateTime does not have any format itself, it holds the information about the date and the time. If you create an OffsetDateTime just from a date it will get the default time information of 0 hours, minutes, seconds and nanos.
You can output it in various formats using a DateTimeFormatter and create a new instance of OffsetDateTime adding temporal units to an existing one like this:
public static void main(String[] args) {
// example OffsetDateTime
OffsetDateTime offsetEndDt = OffsetDateTime.of(2020, 3, 14, 0, 0, 0, 0,
ZoneOffset.UTC);
// define a formatter for the output
DateTimeFormatter myFormatter = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.nnnnnnnnn xxx");
// print it using the previously defined formatter
System.out.println(offsetEndDt.format(myFormatter));
// create a new OffsetDateTime with time information
OffsetDateTime realEndOfDay = offsetEndDt
.withHour(23)
.withMinute(59)
.withSecond(59)
.withNano(999999000);
// print that, too
System.out.println(realEndOfDay.format(myFormatter));
}
It produces the following output using the pattern your example desired output has:
2020-03-14T00:00:00.000000000 +00:00
2020-03-14T23:59:59.999999000 +00:00
First allow me to suggest that you represent the end of your interval NOT as one microsecond before the next day begins, but AS the first moment of the next day exclusive. So a point in time is inside your interval if it is strictly before your end time. This is philosophically more correct. And it rules out the possibility of falsely excluding a point in time within the last 999 nanoseconds of the day from your interval.
// Construct an example java.util.Date for the demonstration
Instant exampleInstant = LocalDate.of(2020, Month.MARCH, 14)
.atStartOfDay(ZoneId.systemDefault())
.toInstant();
Date enddt = Date.from(exampleInstant);
System.out.println("Example java.util.Date: " + enddt);
OffsetDateTime edt = enddt.toInstant()
.atZone(ZoneId.systemDefault())
.plusDays(1)
.truncatedTo(ChronoUnit.DAYS)
.toOffsetDateTime();
System.out.println("End: " + edt);
As one interpretation of EST (of several possible) I have run this code in America/Atikokan time zone (America/Winnipeg gave me EDT). The output was:
Example java.util.Date: Sat Mar 14 00:00:00 EST 2020
End: 2020-03-15T00:00-05:00
If you insist on getting the time 1 microsecond before the new day starts, subtract a microsecond:
OffsetDateTime edt = enddt.toInstant()
.atZone(ZoneId.systemDefault())
.plusDays(1)
.truncatedTo(ChronoUnit.DAYS)
.minus(1, ChronoUnit.MICROS)
.toOffsetDateTime();
End: 2020-03-14T23:59:59.999999-05:00
The below lines of code worked.
Date enddt = someService.getEndDate();
Calendar cal = Calendar.getInstance();
cal.setTime(enddt);
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH);
int day = cal.get(Calendar.DAY_OF_MONTH);
OffsetDateTime edt = OffsetDateTime.of(year,month+1,day,23,59,59,999999000,OffsetDateTime.now().toZonedDateTime().getOffset());

Java Duration error from a day to another

I found a very simple problem using Java Duration.
LocalTime SaturdayStart = LocalTime.of(22, 30);
LocalTime SaturdayEnd = LocalTime.of(01, 00);
System.out.println(SaturdayStart);
System.out.println(SaturdayEnd);
System.out.println(Duration.between(SaturdayStart, SaturdayEnd));
The output from this code is:
22:30
01:00
PT-21H-30M
And this is the problem. Instead of 21H, I wanted the duration to be 2H-30M. What is causing the method to be unable to see the "day change" between the two times?
Remember that LocalTime just represents a single time, in one day, without a time zone.
Since it represents the time you see on the clock in one day, you can't use it to calculate differences between 22:30 today and 01:00 the next day. Your two LocalTime object represent 22:30 today, and 01:00 today respectively.
To take the day into account, you need a LocalDateTime. This represents not only a time (without a time zone), but also the date in the ISO-8601 calendar system. You can create the two LocalDateTime objects like this:
LocalDateTime start = LocalDateTime.of(LocalDate.now(), LocalTime.of(22, 30));
LocalDateTime end = start.plusDays(1).withHour(1).withMinute(0);
And then you can get the duration:
Duration d = Duration.between(start, end);
System.out.println(d);
By the way, the - characters you get in your wrong output are not delimiters for different components. They are negative signs. This is because you are subtracting 22:30 from 01:00, which is like subtracting a bigger number from a smaller number, you get a negative number.
The returned Duration interval has data, whether the StartTime occurs after EndTime or not, which can be used for further processing; like this
LocalTime SaturdayStart = LocalTime.of(22, 30);
LocalTime SaturdayEnd = LocalTime.of(01, 00);
System.out.println(SaturdayStart);
System.out.println(SaturdayEnd);
Duration interval = Duration.between(SaturdayStart, SaturdayEnd);
interval = interval.isNegative() ? interval.plusDays(1) : interval;
System.out.println(interval);
java.time.Duration is modelled on ISO-8601 standards and PT-21H-30M means a duration of 21 hours and 30 minutes where the minus sign indicates that the end time is earlier than the start time. Therefore, you can not get what you want unless you consider a date with time and the type representing both, date and time is LocalDateTime. You can choose any date and combine it with a time to get a LocalDateTime.
For any given date, if the start time is after the end time, reset the end date-time to midnight, then add one day to it and finally set its time to the end time.
Once you have the duration, you can create a formatted string by getting the hours, minutes, seconds etc. from it. With Java-9 some more convenience methods were introduced which makes it easier.
Demo:
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class Main {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
LocalTime startTime = LocalTime.of(22, 30);
LocalTime endTime = LocalTime.of(01, 00);
LocalDateTime startDateTime = today.atTime(startTime);
LocalDateTime endDateTime = today.atTime(endTime);
if (startDateTime.isAfter(endDateTime)) {
endDateTime = endDateTime.with(LocalTime.MIN).plusDays(1).with(endTime);
}
Duration duration = Duration.between(startDateTime, endDateTime);
// Default format
System.out.println(duration);
// Custom format
// ####################################Java-8####################################
String formattedDuration = String.format("%dH-%dM-%dS", duration.toHours(), duration.toMinutes() % 60,
duration.toSeconds() % 60);
System.out.println(formattedDuration);
// ##############################################################################
// ####################################Java-9####################################
formattedDuration = String.format("%dH-%dM-%dS", duration.toHoursPart(), duration.toMinutesPart(),
duration.toSecondsPart());
System.out.println(formattedDuration);
// ##############################################################################
}
}
Output:
PT2H30M
2H-30M-0S
2H-30M-0S

Getting the date representation in seconds in Java

I have a date For Eg: 2014-04-22 08:22:41 and I have to get the representation of the date in seconds from GMT-5 timezone which is 12/31/1969 19:00:00.
I have the following code:
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class samp {
public static void main(String args[]) {
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT-5:00"));
long temp;
Date tempDate = null;
temp = 0L;
cal.clear();
try {
tempDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2014-04-22 08:22:41");
} catch (Exception e) {
}
cal.setTime(tempDate);
temp = cal.getTimeInMillis() / 1000L;
cal.clear();
System.out.println("Second representation is " + (int) temp);
}
}
The output is : Second representation is 1398135161
But when I get the same value from Sybase Database I get the value:
select DateDiff(ss,'12/31/1969 19:00:00','04/22/2014 08:22:41') = 1398172961
Why is there a difference between the java result and the database value.
Is there something wring in java code.
Please clarify.
They are using different timezones
your database is working off of your set timezone but in your calendar you are not using the same timezone when you get the millis.
1398135161 * 1000 can equal in millis
Date (America/New_York) Monday, April 21, 2014 10:52:41 PM EDT
Date (GMT) Tuesday, April 22, 2014 2:52:41 AM GMT
it is all relative to timezone.
There are websites like these that can help you out when in doubt
http://www.ruddwire.com/handy-code/date-to-millisecond-calculators/#.U1dtG-bqfCc
http://www.fileformat.info/tip/java/date2millis.htm
As you can find at the oracle documentation site:
http://docs.oracle.com/javase/6/docs/api/java/util/Calendar.html#getTimeInMillis()
getTimeInMillis returns the time in UTC
You can adjust that value to your timezone using:
cal.getTimeZone().getOffset(UTCmilliseconds)
Which (as it is described at http://docs.oracle.com/javase/6/docs/api/java/util/TimeZone.html#getOffset(long)) returns the amount of milliseconds you have to add to UTC time to get your localtime in milliseconds.
Being your zone-adjusted time given by:
cal.setTime(tempDate);
temp = cal.getTimeInMillis();
temp = (temp + (long)(cal.getTimeZone().getOffset(temp)))/ 1000L;
Adjust Date-Time, Not Epoch
You should be thinking about adjusting your date-time value not the epoch.
Use Time Zone, Not Offset
You should probably be using proper time zone names, not a specific offset number because of Daylight Saving Time and other anomalies. Unless you are absolutely certain your date-values were always adjusted by that specific offset.
Avoid j.u.Date
You should be using a decent library rather than the notoriously difficult java.util.Date and .Calendar classes. That means either Joda-Time or the new java.time package in Java 8.
Joda-Time
Here is example code in Joda-Time.
String inputRaw = "2014-01-02 12:34:56";
String input = inputRaw.replace( " ", "T" );
DateTimeZone timeZone = DateTimeZone.forID( "America/Detroit" );
DateTime dateTime = new DateTime( input, timeZone );
long millis = dateTime.getMillis();
Long seconds = ( millis / 1000L );

How to check if time stamp (epoch time) is of today's or yesterday's [android]

I want to convert the time stamp (epoch time) to human readable string.
For that i am using calendar.setTimeInMillis(timeSinceEpoch) function to create the calender object and to get the date time string in human readable format.
I am confused on, How can I find out that the time stamp (epoch time) is of today or yesterday or it is in the same week as per the system's current date and time?
Is there any API's to achieve this in android?
Thanks.
You can use methods:
public static long diff(long time, int field) {
long fieldTime = getFieldInMillis(field);
Calendar cal = Calendar.getInstance();
long now = cal.getTimeInMillis();
return (time/fieldTime - now / fieldTime);
}
private static final long getFieldInMillis(int field) {
// TODO cache values
final Calendar cal = Calendar.getInstance();
long now = cal.getTimeInMillis();
cal.add(field, 1);
long after = cal.getTimeInMillis();
return after - now;
}
and use them this way:
diff(time, Calendar.DAY_OF_YEAR); // 0 - today, 1 - tomorrow, -1 - yesterday
diff(time, Calendar.WEEK_OF_YEAR); // 0 - this week, -1 - last week etc.
Its really simple:
Calendar c=Calendar.getInstance();
c.getTimeInMillis();
String cur_day=String.format("%te %B %tY",c,c,c); // This will give date like 22 February 2012
c.setTimeInMillis(time);//set your saved timestamp
String that_day=String.format("%te %B %tY",c,c,c); //this will convert timestamp into format like 22 February 2012
//you can compare days,months,year,hours,minutes,seconds and milliseconds using above method.you can find various formats in below link
For more formats,please refer http://download.oracle.com/javase/1.5.0/docs/api/java/util/Formatter.html
You can try to use this for detect today date:
public static boolean isDateToday(long milliSeconds) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(milliSeconds);
Date getDate = calendar.getTime();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
Date startDate = calendar.getTime();
return getDate.compareTo(startDate) > 0;
}
i think this is the most efficient way of figuring out if two timestamps are on the same day. plus it's language-independent:
int secondsInADay = 60*60*24;
int daysSinceEpoch1 = timestamp1/secondsInADay;
int daysSinceEpoch2 = timestamp2/secondsInADay;
if( daysSinceEpoch1 == daysSinceEpoch2 )
;//sameday
else if( daysSinceEpoch1 - daysSinceEpoch2 == 1 )
;//timestamp2 is a day before timetamp1
else if( ......
set timestamp1 to the current time if you want to compare to today
java.time
The legacy date-time API (java.util date-time types and their formatting type, SimpleDateFormat etc.) is outdated and error-prone. It is recommended to stop using it completely and switch to java.time, the modern date-time API*.
Solution using java.time, the modern API:
The modern date-time API is rich with intuitive concepts e.g. it provides us with the class, Instant which represents an instantaneous point on the timeline. There is a class called ZonedDateTime which represents a date-time with a time-zone in the ISO-8601 calendar system. In order to switch to a different time unit (e.g. day, hour, minute, week, month etc.), the API provides methods named as prepositions and other spoken English constructs. Learn more about the modern date-time API from Trail: Date Time.
The concepts like today, yesterday, same week etc. are bounds to a timezone e.g a moment today in London can be tomorrow in Singapore. Also, the start of the week is Locale-sensitive e.g. for Locale.France, it starts on Monday whereas for Locale.US, it starts on Sunday.
Demo:
import java.time.DayOfWeek;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.TemporalAdjusters;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
// Test
Stream.of(
1621533017083L,
1621446617083L,
1621619417083L,
1621189684296L,
1621209600000L,
1621814400000L
).forEach(millis -> {
System.out.println(millis);
System.out.println(Instant.ofEpochMilli(millis));
System.out.println("Today: " + isToday(millis, "Europe/London"));
System.out.println("Yesterday: " + isYesterday(millis, "Europe/London"));
System.out.println("In the current week: " + isInTheSameWeek(millis, "Europe/London"));
System.out.println();
});
}
static boolean isToday(long epochMillis, String timezone) {
ZoneId zoneId = ZoneId.of(timezone);
// The start of the day today at this timezone
ZonedDateTime zdtStartOfDayToday = LocalDate.now().atStartOfDay(zoneId);
long millisStartOfDayToday = zdtStartOfDayToday.toInstant().toEpochMilli();
// The start of the next day at this timezone
ZonedDateTime zdtStartOfDayNextDay = LocalDate.now().plusDays(1).atStartOfDay(zoneId);
long millisStartOfDayNextDay = zdtStartOfDayNextDay.toInstant().toEpochMilli();
return (epochMillis >= millisStartOfDayToday && epochMillis < millisStartOfDayNextDay);
}
static boolean isYesterday(long epochMillis, String timezone) {
ZoneId zoneId = ZoneId.of(timezone);
// The start of the day today at this timezone
ZonedDateTime zdtStartOfDayToday = LocalDate.now().atStartOfDay(zoneId);
long millisStartOfDayToday = zdtStartOfDayToday.toInstant().toEpochMilli();
// The start of the day yesterday at this timezone
ZonedDateTime zdtStartOfDayYesterday = LocalDate.now().minusDays(1).atStartOfDay(zoneId);
long millisStartOfDayYesterday = zdtStartOfDayYesterday.toInstant().toEpochMilli();
return (epochMillis >= millisStartOfDayYesterday && epochMillis < millisStartOfDayToday);
}
static boolean isInTheSameWeek(long epochMillis, String timezone) {
ZoneId zoneId = ZoneId.of(timezone);
// The start of the day today at this timezone
ZonedDateTime zdtStartOfDayToday = LocalDate.now().atStartOfDay(zoneId);
// The start of the week at this timezone
ZonedDateTime zdtStartOfTheWeek = zdtStartOfDayToday.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
long millisStartOfTheWeek = zdtStartOfTheWeek.toInstant().toEpochMilli();
// The start of the next week at this timezone
ZonedDateTime zdtStartOfTheNextWeek = zdtStartOfDayToday.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
long millisStartOfTheNextWeek = zdtStartOfTheNextWeek.toInstant().toEpochMilli();
return (epochMillis >= millisStartOfTheWeek && epochMillis < millisStartOfTheNextWeek);
}
}
Output:
1621533017083
2021-05-20T17:50:17.083Z
Today: true
Yesterday: false
In the current week: true
1621446617083
2021-05-19T17:50:17.083Z
Today: false
Yesterday: true
In the current week: true
1621619417083
2021-05-21T17:50:17.083Z
Today: false
Yesterday: false
In the current week: true
1621189684296
2021-05-16T18:28:04.296Z
Today: false
Yesterday: false
In the current week: false
1621209600000
2021-05-17T00:00:00Z
Today: false
Yesterday: false
In the current week: true
1621814400000
2021-05-24T00:00:00Z
Today: false
Yesterday: false
In the current week: false
ONLINE DEMO
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. 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 and How to use ThreeTenABP in Android Project.
time should be in milli seconds
DateUtils.isToday(time)

Categories

Resources