I have two timestamps and a localized date that I use to find the timezone offset and add it to these dates. How can I calculate the time offset between dates simpler? My method doesn't work with negative values (if (tsOffset.toSecondOfDay() > 0 always true).
fun parseDateTime(startTs: Long, endTs: Long, localizedDateTime: String): Pair<String, String> {
val dateUtcStart = LocalDateTime.ofInstant(Instant.ofEpochMilli(startTs), ZoneOffset.UTC)
val dateUtcEnd = LocalDateTime.ofInstant(Instant.ofEpochMilli(endTs), ZoneOffset.UTC)
val formatter = DateTimeFormatterBuilder()
.parseCaseInsensitive()
.parseDefaulting(ChronoField.YEAR_OF_ERA, dateUtcStart.year.toLong())
.append(DateTimeFormatter.ofPattern("E dd MMM hh:mm a"))
.toFormatter(Locale.ENGLISH)
val localDateTime = LocalDateTime.parse(localizedDateTime, formatter)
val localTs = Timestamp.valueOf(localDateTime).time
val tsOffset = LocalTime.ofInstant(Instant.ofEpochMilli(localTs - startTs), ZoneOffset.systemDefault())
val tzString = if (tsOffset.toSecondOfDay() > 0) "+$tsOffset" else tsOffset.toString()
val startDate = dateUtcStart.toString() + tzString
val endDate = dateUtcEnd.toString() + tzString
return Pair(startDate, endDate)
}
#Test
fun parseDateTime() {
val pair1 = parseDateTime(1626998400000, 1627005600000, "Fri 23 Jul 10:30 am")
val pair2 = parseDateTime(1626998400000, 1627005600000, "Thu 22 Jul 11:30 pm")
// pass
assertEquals("2021-07-23T00:00+10:30", pair1.first)
assertEquals("2021-07-23T02:00+10:30", pair1.second)
// fails
assertEquals("2021-07-23T00:00-00:30", pair2.first)
assertEquals("2021-07-23T02:00-00:30", pair2.second)
}
Also I tried
val dur = Duration.between(dateUtcStart, localDateTime)
But don't sure how to convert it in the string or add to the dates properly.
Here startTs - start of an event timestamp. endTs - end of this event timestamp. localizedDateTime is used to show the start time in the actual time zone (real city) while timestamps show time in UTC. I need to extract this timezone from localizedDateTime and add it to start and end string dateTimes (start = "2021-07-23T00:00+10:30", end = "2021-07-23T02:00+10:30" for startTs = 1626998400000 and endTs = 1627005600000 accordingly).
It’s no simpler than your code, on the contrary, but it fixes a couple of issues that you had.
Disclaimer: I haven’t got your Pair class and I cannot write nor run Kotlin. So I am printing the resulting strings from withint the method, which you will have to change for your purpose. And you will have to hand translate my Java.
private static void parseDateTime(long startTs, long endTs, String localizedDateTime) {
// startTs and localizedDateTime are both representations of the event start time.
// Use this information to obtain the UTC offset of the local time.
Instant startInstant = Instant.ofEpochMilli(startTs);
OffsetDateTime startUtc = startInstant.atOffset(ZoneOffset.UTC);
// Corner case: the local year may be different from the UTC year if the event is close to New Year.
// Check whether this is the case. First get the UTC month and the local month.
Month utcMonth = startUtc.getMonth();
DateTimeFormatter baseSyntaxFormatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(DateTimeFormatter.ofPattern("E dd MMM hh:mm a"))
.toFormatter(Locale.ENGLISH);
Month localMonth = baseSyntaxFormatter.parse(localizedDateTime, Month::from);
int utcYear = startUtc.getYear();
int localYear;
if (utcMonth.equals(Month.DECEMBER) && localMonth.equals(Month.JANUARY)) {
// Local date is in the following year
localYear = utcYear + 1;
} else if (utcMonth.equals(Month.JANUARY) && localMonth.equals(Month.DECEMBER)) {
localYear = utcYear - 1;
} else {
localYear = utcYear;
}
DateTimeFormatter finalFormatter = new DateTimeFormatterBuilder()
.append(baseSyntaxFormatter)
.parseDefaulting(ChronoField.YEAR_OF_ERA, localYear)
.toFormatter(Locale.ENGLISH);
LocalDateTime startLocal = LocalDateTime.parse(localizedDateTime, finalFormatter);
// Now calculate offset
Duration durationOfOffset = Duration.between(startUtc.toLocalDateTime(), startLocal);
ZoneOffset offset = ZoneOffset.ofTotalSeconds(Math.toIntExact(durationOfOffset.getSeconds()));
String startString = startLocal.atOffset(offset).toString();
// Calculate end date and time
String endString = Instant.ofEpochMilli(endTs)
.atOffset(offset)
.toString();
System.out.format("%s - %s%n", startString, endString);
}
Let’s try it with your example data:
parseDateTime(1_626_998_400_000L, 1_627_005_600_000L, "Fri 23 Jul 10:30 am");
parseDateTime(1_626_998_400_000L, 1_627_005_600_000L, "Thu 22 Jul 11:30 pm");
Output:
2021-07-23T10:30+10:30 - 2021-07-23T12:30+10:30
2021-07-22T23:30-00:30 - 2021-07-23T01:30-00:30
You notice that the local start times are now 10:30 and 23:30 as in your input strings, which I believe corrects an error that you had.
Let’s also try an example that bridges New Year:
Instant start = Instant.parse("2021-01-01T00:00:00Z");
parseDateTime(start.toEpochMilli(),
start.plus(2, ChronoUnit.HOURS).toEpochMilli(),
"Thu 31 Dec 10:30 pm");
2020-12-31T22:30-01:30 - 2021-01-01T00:30-01:30
I have used basically the same way of calculating the offset that you present in your own answer.
Issues with your code
First, as I said, the times that your unit test asserts do not agree with the times in your input. For the required output you have taken the UTC time of day and combined with the local offset, which gives a different point in time. A UTC offset is always used with a time of day at that offset (for UTC time of day one would use either offset Z or +00:00).
Consider having your method return a Pair<OffsetDateTime, OffsetDateTime>, not a Pair<String, String>. Strings are for presentation to the user and sometimes for data exchange. Inside your program you should use proper date-time objects, not strings.
As I said in the comments, New Year doesn’t happen at the same time in all time zones. So the year that you get from dateUtcStart.year.toLong() needs not be the year that was assumed in the string from a different time zone. My code takes this into account.
Don’t involve the Timestamp class. It’s poorly designed and long outdated. All it gives you is an extra conversion, hence extra complication.
Your basic problem was using a LocalTime for a duration that might be positive or negative. A LocalTime is for a time of day, not for an amount of time. Your own solution already got rid of this problem.
This is wrong:
val startDate = dateUtcStart.toString() + tzString
First, you should not want to use string manipulation for date and time math. The classes from java.time that you are using produce the string that you need more easily and with less risk of errors. Second, you have indeed got an error here: you are appending the calculated offset to a string that is in UTC, that is, assumes offset 0 (or Z). This was why you were in fact able to produce the incorrect results that your unit test expected.
I got an answer on the Kotlin forum:
val duration = Duration.between(dateUtcStart, localDateTime)
val offset = ZoneOffset.ofTotalSeconds(duration.seconds.toInt())
val startDate = dateUtcStart.atOffset(offset).toString()
val endDate = dateUtcEnd.atOffset(offset).toString()
Related
I have to find out number of days between a given Time and current time. Given time is in ISO format and one example is "2021-01-14 16:23:46.217-06:00".
I have tried it using "java.text.SimpleDateFormat" but it's not giving me accurate results.
In Below Given date, for today's time I am getting output as "633" Days which isn't correct. somehow after parsing it is taking date as "21 december 2020" which isn't correct
String TIMESTAMP_FORMAT = "YYYY-MM-DD hh:mm:ss.s-hh:mm" ;
int noOfDays = Utility.getTimeDifferenceInDays("2021-01-14 16:23:46.217-06:00", TIMESTAMP_FORMAT);
public static int getTimeDifferenceInDays(String timestamp, String TIMESTAMP_FORMAT) {
DateFormat df = new SimpleDateFormat(TIMESTAMP_FORMAT);
try {
Date date = df.parse(timestamp);
long timeDifference = (System.currentTimeMillis() - date.getTime());
return (int) (timeDifference / (1000*60*60*24));
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
}
Looking for a better solution which gives me correct number of days. Thanks
Use java.time API
Classes Date and SimpleDateFormat are legacy.
Since Java 8 (which was released 10 years ago) we have a new Time API, represented by classes from the java.time package.
To parse and format the data, you can use DateTimeFormatter. An instance of DateTimeFormatter can be obtained via static method ofPattern(), or using DateTimeFormatterBuilder.
ofPattern():
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSXXX");
DateTimeFormatterBuilder:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd HH:mm:ss.") // main date-time part
.appendValue(ChronoField.MILLI_OF_SECOND, 3) // fraction part of second
.appendOffset("+HH:MM", "+00:00") // can be substituted with appendPattern("zzz") or appendPattern("XXX")
.toFormatter();
The string "2021-01-14 16:23:46.217-06:00", which you've provided as an example, contains date-time information and UTC offset. Such data can be represented by OffsetDateTime.
To get the number of days between two temporal objects, you can use ChronoUnit.between() as #MC Emperor has mentioned in the comments.
That's how the whole code might look like:
String toParse = "2021-01-14 16:23:46.217-06:00";
OffsetDateTime dateTime = OffsetDateTime.parse(toParse, formatter);
System.out.println("parsed date-time: " + dateTime);
Instant now = Instant.now();
long days = ChronoUnit.DAYS.between(dateTime.toInstant(), now);
System.out.println("days: " + days);
Output:
parsed date-time: 2021-01-14T16:23:46.217-06:00
days: 615
Note that since in this case you need only difference in days between the current date instead of OffsetDateTime you can use LocalDateTime, UTC offset would be ignored while parsing a string. If you decide to do so, then the second argument passed to ChronoUnit.between() should be also of type LocalDateTime.
I'm parsing a timestamp which is "2022-01-12T17:17:34.512492+0000", this format is "yyyy-MM-dd'T'HH:mm:ss.SSSSSS'ZZZZ" (ISO8601).
I want to convert it in epoch unix time, I'm using java.text.SimpleDateFormat.
I tried two methods but both don't work:
1- First Method
val parsed = "2022-01-12T17:17:34.512492+0000"
val df: SimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'ZZZZ'")
val date = df.parse(parsed.toString)
val epoch = date.getTime
Error showed:
java.text.ParseException: Unparseable date: "2022-01-12T17:17:34.512492+0000"
2- This second Method shows an output but is incorrect
val parsed = "2022-01-12T17:17:34.512492+0000"
val df: SimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'+0000'")
val date = df.parse(parsed.toString)
val epoch = date.getTime
println(epoch)
Output:
1642004766492
If you convert this epoch to HUMAN DATE: "Wednesday, 12 January 2022 16:26:06.492"
The hours,minutes and seconds are wrong.
SimpleDateFormat is outdated, as Gael pointed out.
The Time API now supports up to nanoseconds, so microseconds are not an issue here. You should use DateTimeFormatter with ZonedDateTime. Your pattern is slightly wrong. Checking the docs for Offset Z:
Offset Z: This formats the offset based on the number of pattern
letters. One, two or three letters outputs the hour and minute,
without a colon, such as '+0130'. The output will be '+0000' when the
offset is zero. Four letters outputs the full form of localized
offset, equivalent to four letters of Offset-O. The output will be the
corresponding localized offset text if the offset is zero. Five
letters outputs the hour, minute, with optional second if non-zero,
with colon. It outputs 'Z' if the offset is zero. Six or more letters
throws IllegalArgumentException.
You can also print the time using toInstant to make sure it was parsed correctly:
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
val parsed = "2022-01-12T17:17:34.512492+0000"
val p = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSZZZ"
val dtf = DateTimeFormatter.ofPattern(p)
val zdt = ZonedDateTime.parse(parsed, dtf)
println(zdt.toInstant) // 2022-01-12T17:17:34.512492Z
println(zdt.toInstant.toEpochMilli) // 1642004254512
Here is a nice article that explains in detail converting an ISO 8601 in Java. The comments at the end are particularly useful, as it shows the difference between the different patterns used.
looks like epoch has data in internal datetime format.
and you should convert it to string format
like this in java
public static String dateToString(Date d, String string_format) {
String result = "";
if(d != null) {
result = new SimpleDateFormat(string_format).format(d);
}
return result;
}
The timestamp you have has microseconds precision. Such precision is not supported by SimpleDateFormat. Also, Unix epoch time is usually up to milliseconds precision.
Possible solution here is to explicitly round the microseconds to milliseconds in the string before parsing, then use the yyyy-MM-dd'T'HH:mm:ss.SSSZ format.
String parsed = "2022-01-12T17:17:34.512492+0000";
String upToSeconds = parsed.substring(0, "yyyy-MM-ddTHH:mm:ss".length());
String microseconds = parsed.substring("yyyy-MM-ddTHH:mm:ss.".length(), "yyyy-MM-ddTHH:mm:ss.".length() + "SSSSSS".length());
String timezone = parsed.substring("yyyy-MM-ddTHH:mm:ss.SSSSSS".length());
String roundedMilliseconds = new BigDecimal(microseconds).divide(new BigDecimal("1000"), 0, RoundingMode.HALF_UP).toString();
String reformatted = upToSeconds + "." + roundedMilliseconds + timezone;
System.out.println(reformatted); // 2022-01-12T17:17:34.512+0000
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
long epoch = sdf.parse(reformatted).getTime();
System.out.println(epoch); // 1642007854512
System.out.println(Instant.ofEpochMilli(epoch)); // 2022-01-12T17:17:34.512Z
I am getting a time string that is the sunrise/sunset times in UTC in format HH:mm
example:
09:35
Currently I am doing this to convert the given time to the current date UTC using the java.time library
val utcZoneId = ZoneId.of("UTC")
val now = Instant.now()
val dateTimeFormater:DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd").withZone(utcZoneId)
val date = dateTimeFormater.format(now)
val fullDateSunrise = "${date}T${data[0].sunrise}:00"
val local = LocalDateTime.parse(fullDateSunrise, DateTimeFormatter.ISO_LOCAL_DATE_TIME)
val final = local.atZone(utcZoneId)
val utcSunrise = final.toInstant().toEpochMilli()
val fullDateSunset = "${date}T${data[0].sunset}:00"
val local2 = LocalDateTime.parse(fullDateSunset, DateTimeFormatter.ISO_LOCAL_DATE_TIME)
val final2 = local2.atZone(utcZoneId)
val utcSunset = final2.toInstant().toEpochMilli()
I then pass the UTC milliseconds back the the client once I have them
It works how I need it to but I can help but feel there must be an easier way than getting a formatted UTC date string and combining that with the given time and then converting that to an actual DateTime object.
So the question is, is there an easier way to do this?
Sure, you definitely don't need to parse back and forth to strings. I assume an input of 09:35 means: At 09:35, local time, the sun will rise. Note that you're confusing things; UTC is a zone, an input like 09:35 is zoneless. I doubt this stamp represent 'UTC'; it would mean that the correct value for the sunrise today for Tokyo is -5:25, as it'll be 19:25, the previous day, in the UTC timezone when the sun rose in tokyo today.
Once you stop using the UTC zone it becomes muuuch simpler:
DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("HH:mm");
LocalDateTime sunriseToday = LocalDateTime.now().with(LocalTime.parse("04:35", TIME_FORMAT));
ZonedDateTime inTokyo = sunriseToday.atZone(ZoneId.of("Asia/Tokyo"));
return inTokyo.toInstant().toEpochMilli();
Note that this would return the exact moment in time when the sun rises in tokyo. Printing it as an ISO stamp, that'd be 2020-06-09T19:35Z.
If you really want the epoch-millis that match 2020-06-10T04:35Z - which to be clear makes no sense, that is NOT when the sun rose in tokyo at all today! - then...
DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("HH:mm");
LocalDateTime sunriseToday = LocalDateTime.now().with(LocalTime.parse("04:35", TIME_FORMAT));
ZonedDateTime inTokyo = sunriseToday.atZone(ZoneId.of("Asia/Tokyo"));
ZoneDateTime thisMakesNoSense = inTokyo.withZoneSameLocal(ZoneOffset.UTC);
return thisMakesNoSense.toInstant().toEpochMilli();
You don't have to convert Strings, use a ZonedDateTime instead and provide a desired zone.
Use some fun like this one:
fun convertToEpochMillis(time: String, zoneId: ZoneId): Long {
// parse the time to a LocalTime
val localTime = LocalTime.parse(time, DateTimeFormatter.ofPattern("HH:mm"))
// create a ZonedDateTime from the current date, the parsed time the given time zone
val zonedDateTime = ZonedDateTime.of(LocalDate.now(), localTime, zoneId)
// then return the representation of the instant in epoch millis
return zonedDateTime.toInstant().toEpochMilli()
}
and use it in a fun main() as follows
fun main() {
// define / receive a time
val time = "09:35"
// and a zone identifier
var zone = "UTC"
// use the method
val utcSunriseMillis = convertToEpochMillis(time, ZoneId.of(zone))
// and print a result statement
println("Sunrise time ${time} in ${zone} is ${utcSunriseMillis}")
// change the zone and do the same again with a different zone, just to see what happens...
zone = "America/Los_Angeles"
val laSunriseMillis = convertToEpochMillis(time, ZoneId.of(zone))
println("Sunrise time ${time} in ${zone} is ${laSunriseMillis}")
}
which then prints today (=> 2020-06-10)
Sunrise time 09:35 in UTC is 1591781700000
Sunrise time 09:35 in America/Los_Angeles is 1591806900000
I have been trying to convert local time (EST) to UTC and vice versa. So, I present a time picker, user selects the time, I convert the same to UTC and send to server. Here's the code:
val cal = Calendar.getInstance()
cal.set(Calendar.HOUR_OF_DAY, mHour) //mHour = 15
cal.set(Calendar.MINUTE, mMinute) //mMinute = 00
cal.set(Calendar.SECOND, 0)
val formatter = SimpleDateFormat("HH:mm:ss")
formatter.timeZone = TimeZone.getTimeZone("UTC")
val cutOffTime = formatter.format(cal.time) //this gives 19:00:00 which is correct
Above output for cutOffTime is correct as 15:00 EST is 19:00 UTC after considering day light savings.
Now, I fetch this same cutOffTime from server, convert it to local (EST) and display. Here's the code:
val cutOffTime = jsonObject.get("cutOffTime").getAsString()) //value is 19:00:00
var cutoffTime: Time? = null
val format = SimpleDateFormat("hh:mm:ss")
format.timeZone = TimeZone.getTimeZone("UTC")
cutoffTime = Time(format.parse(cutOffTime).time)
//cutoffTime has value 14:00 which is strange, it should be 15:00
So, cutoffTime in above code has value 14:00 which is strange, it should be 15:00.
Please note that this code was working before day light savings on March 8, 2020. Any idea what am I doing wrong?
Please don't use the old and badly designed java api for date and times. Use the new java.time api. It's much more robust and is nicer to use.
Here is an example on how to do your code with java.time:
int mHour = 15;
int mMinute = 0;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
ZonedDateTime toFormat = LocalDateTime
.now() // Current date and time.
.withHour(mHour).withMinute(mMinute).withSecond(0) // Change hour, minute and second like in your example.
.truncatedTo(ChronoUnit.SECONDS) // Throw away milliseconds and nanoseconds.
.atZone(ZoneOffset.UTC); // Say that the time is located at UTC+0.
String formatted = formatter
.withZone(ZoneId.of("America/New_York")) // Create a new formatter that formats toFormat to the local time America/New_York.
.format(toFormat);
System.out.println(formatted); // Gives 11:00:00 on my machine now. America/New_York is either UTC-5 or UTC-4.
ZonedDateTime parsed = LocalTime
.parse(formatted, formatter) // Parse the String. The result is an instance of LocalTime.
.atDate(LocalDate.now(ZoneId.of("America/New_York"))) // Add the date values which are those of the current local date at America/New_York.
.atZone(ZoneId.of("America/New_York")); // Create a ZonedDateTime of the LocalDateTime to explicitly define the zone.
Instant pointInTimeA = parsed.toInstant();
Instant pointInTimeB = toFormat.toInstant();
System.out.println(pointInTimeA.equals(pointInTimeB)); // Gives true because both describe the same point in time as they should.
The great benefit is that the api will handle everything regarding summertime and wintertime for you. Have read here for information about the EST and why you shouldn't use it.
The problem you face is probably due to the fact that you used HH in one formatter but hh in the other one. Those are not the same. Have read here about Patterns for Formatting and Parsing.
I ended up with below solution. I knew the format of the string from server, so I split it. I didn't want to use the new time API since it is available from API level 26 onwards.
val cutOffString = jsonObject.get("cutOffTime").getAsString() //UTC date 19:00:00 from server
val cal = Calendar.getInstance()
cal.set(Calendar.HOUR_OF_DAY, cutOffString.split(":")[0].toInt())
cal.set(Calendar.MINUTE, cutOffString.split(":")[1].toInt())
cal.set(Calendar.SECOND, 0)
cal.timeZone = TimeZone.getTimeZone("UTC")
val cutoffTime: Time = Time(cal.time.time) //15:00:00
I am saving date's in a file in the following format as a string.
Sat Jul 21 23:31:55 EDT 2012
How can I check if 24 hours have passed? I am a beginner so please explain it a little bit =)
I am not sure if I completely understood the question - do you have two dates for comparison or do you wish to keep checking periodically if 24 hours have elapsed?
If comparing two date/times, I would suggest looking at joda or perhaps date4j. Using joda, one could look into using interval between two dates:
Interval interval = new Interval(previousTime, new Instant());
where previous time would be the time you mentioned
You can do something like this:
try {
// reading text...
Scanner scan = new Scanner( new FileInputStream( new File( "path to your file here..." ) ) );
String dateString = scan.nextLine();
// creating a formatter.
// to understand the format, take a look here: http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
// EEE: Day name of week with 3 chars
// MMM: Month name of the year with 3 chars
// dd: day of month with 2 chars
// HH: hour of the day (0 to 23) with 2 chars
// mm: minute of the hour with 2 chars
// ss: second of the minute with 2 chars
// zzz: Timezone with 3 chars
// yyyy: year with 4 chars
DateFormat df = new SimpleDateFormat( "EEE MMM dd HH:mm:ss zzz yyyy", Locale.US );
// parsing the date (using the format above, that matches with your date string)
Date date = df.parse( dateString );
// now!
Date now = new Date();
// gets the differente between the parsed date and the now date in milliseconds
long diffInMilliseconds = now.getTime() - date.getTime();
if ( diffInMilliseconds < 0 ) {
System.out.println( "the date that was read is in the future!" );
} else {
// calculating the difference in hours
// one hour have: 60 minutes or 3600 seconds or 3600000 milliseconds
double diffInHours = diffInMilliseconds / 3600000D;
System.out.printf( "%.2f hours have passed!", diffInHours );
}
} catch ( FileNotFoundException | ParseException exc ) {
exc.printStackTrace();
}
I would suggest storing your information as a java.util.Calendar which has a compareTo ()function.
If you want to compare now to current time, you can use System.getCurrentTimeMillis() to get the current time.
Define A Day
Do you really mean one day or 24-hours? Because of Daylight Saving Time nonsense, a day can vary in length such as 23 or 25 hours in the United States.
Avoid 3-Letter Time Zone Codes
That String format is a terrible representation of a date-time. It is difficult to parse. It uses a 3-letter time zone code, and such codes are neither standardized nor unique. If possible, choose another format. The obvious choice is ISO 8601, for example: 2014-07-08T04:17:01Z.
Use proper time zone names.
Avoid j.u.Date & .Calendar
The java.util.Date and .Calendar classes bundled with Java are notoriously troublesome. Avoid them.
Instead use either the venerable Joda-Time library or the new java.time package bundled in Java 8 (and inspired on Joda-Time).
Joda-Time
Here is some example code in Joda-Time.
Get the current moment.
DateTime now = DateTime.now();
Parse the input string.
String input = "Sat Jul 21 23:31:55 EDT 2012";
DateTime formatter = DateTimeFormat.forPattern( "EEE MMM dd HH:mm:ss zzz yyyy" ).with Locale( java.util.Locale.ENGLISH );
DateTime target = formatter.parseDateTime( input );
Calculate 24 hours (or next day).
DateTime twentyFourHoursLater = target.plusHours( 24 );
Test if current moment happened after.
boolean expired = now.isAfter( twentyFourHoursLater );
Or, if you want next day rather than 24-hours, use plusDays rather than plusHours. If necessary, adjust to desired time zone. Time zone is crucial as it defines the day/date and applies rules for anomalies such as Daylight Saving Time.
DateTime targetAdjusted = target.withZone( DateTimeZone.forID( "Europe/Paris" ) );
…
DateTime aDayLater = targetAdjusted.plusDays( 1 ); // Go to next day, accounting for DST etc.
boolean expired = now.isAfter( aDayLater ); // Test if current moment happened after.