I have some legacy KML documents which includes a time stamp entry.
Why is the below date not valid when using Instant to parse? Both methods are suppose to parse ISO 8601 formatted dates.
String dateString = "2017-12-04T08:06:60Z"
Using
java.time.Instant.parse(dateString)
throws an error
"DateTimeParseException Text 2017-12-04T08:06:60Z could not be parsed at index 0."
However, when using
Date myDate = javax.xml.bind.DatatypeConverter.parseDateTime( dateString )
myDate is parsed correctly....
60 seconds isn't a valid time. Meaning that this is invalid 2017-12-04T08:06:60Z, if it was 60 seconds then the minute should have incremented and your time would be 2017-12-04T08:07:00Z
Using a valid date and then parsing the String would work just fine:
String date = "2017-12-04T08:07:00Z";
System.out.println(Instant.parse(date));
Also java.time ignores leap seconds. From the docs:
Implementations of the Java time-scale using the JSR-310 API are not
required to provide any clock that is sub-second accurate, or that
progresses monotonically or smoothly. Implementations are therefore
not required to actually perform the UTC-SLS slew or to otherwise be
aware of leap seconds. JSR-310 does, however, require that
implementations must document the approach they use when defining a
clock representing the current instant. See Clock for details on the
available clocks.
The accepted answer is fine. I just have two things to add:
You can parse the string with the invalid second value of 60 by using ResolverStyle.LENIENT.
Since Jon Skeet in a comment mentioned a possible leap second: It’s not a valid leap second. java.time does support the parsing of a (valid) leap second.
Parsing your string
DateTimeFormatter lenientFormatter
= DateTimeFormatter.ISO_OFFSET_DATE_TIME
.withResolverStyle(ResolverStyle.LENIENT);
String dateString = "2018-12-04T08:06:60Z";
Instant myInstant = lenientFormatter.parse(dateString, Instant::from);
System.out.println(myInstant);
Output:
2018-12-04T08:07:00Z
So the overflowing second value of 60 has been rolled into a full minute.
By the way, javax.xml.bind.DatatypeConverter.parseDateTime parses into a Calendar (not a Date), which is how the returned object can in fact hold a second value of 60. It seems that it generally accepts a second value of 60, but throws an exception on 61.
Parsing a valid leap second
This does in no way answer your question, but I thought that it might be useful for future readers. A leap second is always the last second of the day, so 23:59:60. An Instant cannot hold this value, but you can query whether one was parsed. It’s supported via DateTimeFormatterBuilder.appendInstant(), and DateTimeFormatter.parsedLeapSecond().
DateTimeFormatter leapSecondFormatter = new DateTimeFormatterBuilder()
.appendInstant()
.toFormatter();
Instant myInstant
= leapSecondFormatter.parse("2018-12-04T23:59:60Z", Instant::from);
System.out.println(myInstant);
TemporalAccessor parsed = leapSecondFormatter.parse("2018-12-04T23:59:60Z");
System.out.println("Instant: " + parsed.query(Instant::from));
System.out.println("Was a leap second parsed? "
+ parsed.query(DateTimeFormatter.parsedLeapSecond()));
Output:
2018-12-04T23:59:59Z
Instant: 2018-12-04T23:59:59Z
Was a leap second parsed? true
I don’t know why it had to be this complicated, but it works.
Link: Documentation of DateTimeFormatter.parsedLeapSecond
Related
I have a time in milliseconds: 1618274313.
When I convert it to time using this website: https://www.epochconverter.com/, I am getting 6:08:33 AM.
But when I use SimpleDateFormat, I am getting something different:
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
System.out.println(sdf.format(new Date(1618274313)));
I am getting output as 23:01:14.
What is the issue in my code?
In your example, you are using time 1618274313 and you are assuming that it is in milliseconds. However, when I entered the same time on https://www.epochconverter.com/, I got below results:
Please notice the site mentions: Assuming that this timestamp is in seconds.
Now if we use that number multiplied by 1000 (1618274313000) as the input so that the site considers it in milliseconds, we get below results:
Please notice the site now mentions: Assuming that this timestamp is in milliseconds.
Now, when you will use 1618274313000 (correct time in milliseconds) in Java with SimpleDateFormat, you should get your expected result (instead of 23:01:14):
SimpleDateFormat sdf=new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
System.out.println(sdf.format(new Date(1618274313000)));
use Instant.ofEpochSecond
long test_timestamp = 1618274313L;
LocalDateTime triggerTime =
LocalDateTime.ofInstant(Instant.ofEpochSecond(test_timestamp),
TimeZone.getDefault().toZoneId());
System.out.println(triggerTime);
it prints output as 2021-04-13T06:08:33
Assuming it is in milliseconds as you say, all you know for certain is that you have a specific duration.
Duration d = Duration.ofMillis(1618274313);
System.out.println(d);
Prints
PT449H31M14.313S
Which says it is 449 hours, 31 minutes and 14.313 seconds of duration. Without knowing the epoch of this duration and any applicable zone offsets, it is not really possible to ascertain the specific date/time it represents. I could make lots of assumptions and provide results based on that, but more information from you would be helpful.
java.time
As Viral Lalakia already spotted, the epoch converter that you linked to, explicitly said that it assumed that the number was seconds (not milliseconds) since the epoch. The following makes the same assumption in Java. I recommend that you use java.time, the modern Java date and time API.
ZoneId zone = ZoneId.of("Asia/Kolkata");
long unixTimestamp = 1_618_274_313;
Instant when = Instant.ofEpochSecond(unixTimestamp);
ZonedDateTime dateTime = when.atZone(zone);
System.out.println(dateTime);
System.out.println(dateTime.format(DateTimeFormatter.ISO_LOCAL_TIME));
Output is:
2021-04-13T06:08:33+05:30[Asia/Kolkata]
06:08:33
This agrees with the 6:08:33 AM that you got from the converter. And the date is today’s date. A coincidence?
If the number is indeed milliseconds (which I honestly doubt), just use Instant.ofEpochMill() instead of Instant.ofEpochSecond().
Instant when = Instant.ofEpochMilli(unixTimestamp);
1970-01-19T23:01:14.313+05:30[Asia/Kolkata]
23:01:14.313
This in turn agrees with the result you got in Java (except that the milliseconds are also printed).
I tried to remove minute from given time, but some how it is converting time to my local time zone
String timeStamp="20180623 05:58:15" ;
dateFormat inputFormatter = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
Date date = inputFormatter.parse(timeStamp);
date.setMinutes(-2);
logger.info("Before converting : "+date);
DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
Here it is converting to my local time and subtracting 2 minutes from given time, but I don`t want to check the time zone here instead, what ever time I give it should just subtract 2 minutes.
Start with understanding into how Date works. When you do...
logger.info("Before converting : "+date);
The Date class uses it's toString method to format the the date/time information represented by the Date class into a human readable format. It doesn't "convert" the date/time value in anyway
So taking your code from above (and reworking it so it works), it outputs...
Before converting : Sat Jun 23 04:58:15 AEST 2018
20180623 04:58:15
on my machine - why are the values the same? Because the input doesn't have any time zone information, so the time is likely been treated as been in the machines local timezone (and the value is simply been formatted for output).
Date is just a container for the number of milliseconds since the Unix Epoch, it's format agnostic - meaning it carries not formatting information.
Date is also effectively deprecated - not to mention that setDate is also very much deprecated
A better (starting point) overall is to make use the newer date/time API introduced in Java 8 (and which has back port support for earlier versions of the API)
String timeStamp = "20180623 05:58:15";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss", Locale.ENGLISH);
LocalDateTime ldt = LocalDateTime.parse(timeStamp, formatter);
ldt = ldt.minusMinutes(2);
System.out.println(ldt);
System.out.println(ldt.format(formatter));
This will output...
2018-06-23T05:56:15
20180623 05:56:15
The input and the output are still consider as been in the machines local time zone.
but I don`t want to check the time zone here instead, what ever time I give it should just subtract 2 minutes
Just remember, the API still needs to have some concept of time zone, weather it's the local time zone or UTC/GMT, but since your input doesn't provide any kind of information, you need to make a choice over "how" best to handle that issue. The example above just "assumes" local time, but you could use ZonedDateTime and convert it to "common" time zone from which your operations are executed or, better yet, make all your strings carry time zone information
Oh, and for the love of my sanity, stop managing date/time values in String format - get them into an appropriate container as soon as possible and manage them from there - I've spent a week wrangling inappropriately formatted date strings and I'm not happy Jan, not happy
I have the following date
2017-08-23-11.19.02.234850
it has the following date format
yyyy-MM-dd-HH.mm.ss.SSSSSS
What I want to do is to convert the date to format yyyy-MM-dd'T'HH:mm:ss.SSSSSS
I have the following code
public static void main(String[] args) {
String strDate = "2017-08-23-11.19.02.234850";
String dateFmt = "yyyy-MM-dd-HH.mm.ss.SSSSSS";
System.out.println("converted Date: " + convertDate(strDate, dateFmt));
}
public static String convertDate(String strDate, String format) {
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.US);
sdf.setLenient(true);
try {
Date dateIn = sdf.parse(strDate);
return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS").format(dateIn);
}catch(ParseException e) {
e.printStackTrace();
}
return "";
}
the result is
converted Date: 2017-08-23T11:22:56.000850
input date 2017-08-23-11.19.02.234850
converted date 2017-08-23T11:22:56.000850
doesn't look the same, it seems java is rounding the milliseconds besides if I turn lenient off for date validation
sdf.setLenient(false);
I get the following
java.text.ParseException: Unparseable date: "2017-08-23-11.19.02.234850"
at java.text.DateFormat.parse(Unknown Source)
at mx.santander.canonical.datamodel.enums.Main.convertDate(Main.java:74)
at mx.santander.canonical.datamodel.enums.Main.main(Main.java:66)
converted Date:
How to build a function which validates and converts date strings like this in a proper way?
EDIT:
I added a new function to obtain results
/**
* Gets the ISO 8601 date str from string.
*
* #param strDate the str date
* #return the ISO 8601 date str from string
*/
private String getISO8601DateStrFromString (String strDate) {
String responseISO8601Date = "";
if(strDate == null || "".equals(strDate.trim())) {
return responseISO8601Date;
}
try {
String strDtWithoutNanoSec = strDate.substring(0, strDate.lastIndexOf("."));
String strDtNanoSec = strDate.substring(strDate.lastIndexOf(".") + 1, strDate.length());
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH.mm.ss");
formatter.setLenient(false);
Date date = formatter.parse(strDtWithoutNanoSec);
Timestamp t = new Timestamp(date.getTime());
t.setNanos(Integer.parseInt(strDtNanoSec));
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'.'");
NumberFormat nf = new DecimalFormat("000000");
responseISO8601Date = df.format(t.getTime()) + nf.format(t.getNanos());
} catch (ParseException | StringIndexOutOfBoundsException | NumberFormatException e) {
String errorMsg = String.format("The date provided for conversion to ISO 8601 format [%s] is not correct", strDate);
System.out.println(errorMsg);
}
return responseISO8601Date;
}
What I get:
Uptadet date 2017-12-20T11:19:02.234850
As others have already mentioned, your requirement does not fit the use of Date and SimpleDateFormat since these only support milliseconds, that is, three decimals on the seconds, where you have six decimals (microseconds). So we need to find some other way. This is basically a good idea anyway, since Date and SimpleDateFormat are long outdated, and today we have better tools for the job.
I have got two suggestions for you.
java.time
Even in Java 7 I think that it’s a good idea to use the modern Java date and time API that came out with Java 8, AKA JSR-310. Can you do that? Certainly; use the backport for Java 6 and 7, ThreeTen Backport. The modern API supports anything from 0 through 9 decimals on the seconds, and the code is straightforward when you know how:
private static DateTimeFormatter inputParser
= DateTimeFormatter.ofPattern("yyyy-MM-dd-HH.mm.ss.SSSSSS");
private static DateTimeFormatter outputFormatter
= DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS");
public static String convertDate(String strDate) {
return LocalDateTime.parse(strDate, inputParser)
.format(outputFormatter);
}
I am using your own two format pattern strings. convertDate("2017-08-23-11.19.02.234850") returns 2017-08-23T11:19:02.234850.
There is a simplification possible: Since the format you want to obtain, conforms with ISO 8601, you don’t need an explicit formatter for it. The modern classes understand and produce ISO 8601 formats natively, so you may use:
return LocalDateTime.parse(strDate, inputParser).toString();
However, if the decimals on the seconds happened to end in 000, this will not print the last three zeroes. So if six decimals are required even in this case, use the formatter.
Regular expression
If you don’t want to rely on an external library, even temporarily until once you upgrade to Java 8 (or 9), your job can be done with a regular expression:
return strDate
.replaceFirst("^(\\d{4}-\\d{2}-\\d{2})-(\\d{2})\\.(\\d{2})\\.(\\d{2}\\.\\d{6})$",
"$1T$2:$3:$4");
It’s less elegant and harder to read, and it doesn’t offer the level of input validation you get from using a proper date and time API. Other than that, it’s a way through.
java.sql.Timestamp?
As others have said, java.sql.Timestamp offers nanosecond precision and thus will hold your date-time. Parsing your string into a Timestamp isn’t straightforward, though, so I don’t think it’s worth the trouble. Usagi Miyanmoto correctly identifies Timestamp.valueOf() as the method to use, but before you could do that, you would have change the format, so you would end up changing the format twice instead of just once. Or maybe three times since Timestamp also doesn’t produce your desired ISO 8601 format readily. Additionally you would need to decide a time zone for the timestamp, but I assume you could do that without any trouble.
If you needed to keep the the date-time around, a Timestamp object might be worth considering, but again, it’s a long outdated class. In any case, for reformatting alone, I certainly would not use it.
What happened in your code?
SimpleDateFormat understood 234850 as milliseconds, that is, 234 seconds 850 milliseconds. So it added 234 seconds to your time, 11:19:02. And then printed the remaining 850 milliseconds in 6 decimal places as you had requested.
Date has precision only till milli seconds. Please use timestamp instead - it has precision till nano seconds, which is expected in your case.
Please refer this answer - precision till nano seconds
TimeStamp API
A thin wrapper around java.util.Date that allows the JDBC API to
identify this as an SQL TIMESTAMP value. It adds the ability to hold
the SQL TIMESTAMP fractional seconds value, by allowing the
specification of fractional seconds to a precision of nanoseconds. A
Timestamp also provides formatting and parsing operations to support
the JDBC escape syntax for timestamp values.
SimpleDateFormat of Java does not support microsecond in pattern.
java.util.Date format SSSSSS: if not microseconds what are the last 3 digits?
You have several choices:
Manually handle the parsing and formatting of the microseconds
Switch to use Java 8 as Time API supports fraction of second in pattern (https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html)
If you need to use Java 7, consider using JODA Time for your date-time logics. JODA support fraction of second in its DateTimeFormat (http://joda-time.sourceforge.net/apidocs/org/joda/time/format/DateTimeFormat.html)
That result you got is expected. In your format string S were used. S is for milliseconds, hat is thousandths of seconds, and in this case the number of S's does not matter for parsing.
Your input string ends with 11.19.02.234850, the last part is interpreted as an integer value, and added to the date and time as milliseconds. That is as 234.850 seconds. Now, if you add 234 secs to 11:19:02, it becomes 11:22:56, just as you got in the result...
You cannot make a SimpleDateFormat mask that can parse microseconds into a Date, and Date cannot hold microseconds value either.
You have to choose, whether you want to use Date, or really need the finer then milliseconds resolution?
If you stick with Date, you should truncate the string of the last 3 characters.
Or you could use java.sql.Timestamp, which has a valueOf() method, hat uses SQL timestamp format.
Unfortunately it is not exactly he same as yours (being yyyy-[m]m-[d]d hh:mm:ss[.f...])...
Another way could be to split the string by separators (like [-.]), parse them to integers, and use hese integers with the Timestamp() constructor...
I would appreciate any help with finding bug for this exception:
java.text.ParseException: Unparseable date: "2007-09-25T15:40:51.0000000Z"
and following code:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
Date date = sdf.parse(timeValue);
long mills = date.getTime();
this.point.time = String.valueOf(mills);
It throws expcetion with Date date = sdf.parse(timeValue); .
timeValue = "2007-09-25T15:40:51.0000000Z"; , as in exception.
Thanks.
Z represents the timezone character. It needs to be quoted:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
(Answer now extensively revised, thanks for the corrections in the comments)
In Java 7 you can use the X pattern to match an ISO8601 timezone, which includes the special Z (UTC) value.
The X pattern also supports explicit timezones, e.g. +01:00
This approach respects the timezone indicator correctly, and avoids the problem of treating it merely as a string, and thus incorrectly parsing the timestamp in the local timezone rather than UTC or whatever.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
Date date = sdf.parse("2007-09-25T15:40:51Z");
Date date2 = sdf.parse("2007-09-25T15:40:51+01:00");
This can also be used with milliseconds:
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
Date date3 = sdf2.parse("2007-09-25T15:40:51.500Z");
However, as others have pointed out, your format has 7-digit fractional seconds, which are presumably tenth-microseconds. If so, SimpleDateFormat cannot handle this, and you will get incorrect results, because each 0.1 microsecond will be interpreted as a millisecond, giving a potential overall error of up to 10,000 seconds (several hours).
In the extreme case, if the fractional second value is 0.9999999 seconds, that will be incorrectly interpreted as 9999999 milliseconds, which is about 167 minutes, or 2.8 hours.
// Right answer, error masked for zero fractional seconds
Date date6 = sdf2.parse("2007-09-25T15:40:51.0000000Z");
// Tue Sep 25 15:40:51 GMT 2007
// Error - wrong hour
// Should just half a second different to the previous example
Date date5 = sdf2.parse("2007-09-25T15:40:51.5000000Z");
// Tue Sep 25 17:04:11 GMT 2007
This error is hidden when the fractional seconds are zero, as in your example, but will manifest whenever they are nonzero.
This error can be detected in many cases, and its impact reduced, by turning off "lenient" parsing which by default will accept a fractional part of more than one second and carry it over to the seconds/minutes/hours parts:
sdf2.setLenient(false);
sdf2.parse("2007-09-25T15:40:51.5000000Z");
// java.text.ParseException: Unparseable date: "2007-09-25T15:40:51.5000000Z"
This will catch cases where the millis value is more than 999, but does not check the number of digits, so it is only a partial and indirect safeguard against millis/microseconds mismatches. However, in many real-world datasets this will catch a large number of errors and thus indicate the root problem, even if some values slip through.
I recommend that lenient parsing is always disabled unless you have a specific need for it, as it catches a lot of errors that would otherwise be silently hidden and propagated into downstream data.
If your fractional seconds are always zero, then you could use one of the solutions here, but with the risk that they will NOT work if the code is later used on non-zero fractional seconds. You may wish to document this and/or assert that the value is zero, to avoid later bugs.
Otherwise, you probably need to convert your fractional seconds into milliseconds, so that SimpleDateFormat can interpret them correctly. Or use one of the newer datetime APIs.
java.time
I recommend that you use java.time, the modern Java date and time API, for your date and time work. Your string is in ISO 8601 format and can be directly parsed by the java.time.Instant class without us specifying any formatter:
String timeValue = "2007-09-25T15:40:51.0000000Z";
Instant i = Instant.parse(timeValue);
long mills = i.toEpochMilli();
String time = String.valueOf(mills);
System.out.println(time);
Output:
1190734851000
May use a formatter for output if desired
If we know for a fact that the millisecond value will never be negative, java.time can format it into a string for us. This saves the explicit conversion to milliseconds first.
private static final DateTimeFormatter EPOCH_MILLI_FORMATTER
= new DateTimeFormatterBuilder().appendValue(ChronoField.INSTANT_SECONDS)
.appendValue(ChronoField.MILLI_OF_SECOND, 3)
.toFormatter(Locale.ROOT);
Now formatting is trivial:
assert ! i.isBefore(Instant.EPOCH) : i;
String time = EPOCH_MILLI_FORMATTER.format(i);
And output is still the same:
1190734851000
In particular if you need to format Instant objects to strings in more places in your program, I recommend the latter approach.
What went wrong in your code?
First of all, there is no way that SimpleDateFormat can parse 7 decimals of fraction of second correctly. As long as the fraction is zero, the result will happen to come out correct anyway, but imagine a time that is just one tenth of a second after the full second, for example, 2007-09-25T15:40:51.1000000Z. In this case SimpleDateFormat would parse the fraction into a million milliseconds, and your result would be more than a quarter of an hour off. For greater fractions the error could be several hours.
Second as others have said format pattern letter Z does not match the offset of Z meaning UTC or offset zero from UTC. This caused the exception that you observed. Putting Z in quotes as suggested in the accepted answer is wrong too since it will cause you to miss this crucial information from the string, again leading to an error of several hours (in most time zones).
Link
Oracle tutorial: Date Time explaining how to use java.time.
I am not interested in what the current UTC time is in milliseconds, nor do I need to mess with timezones. My original date is already stored as a UTC timestamp.
I have a date stored in a database in UTC time, "2012-06-14 05:01:25".
I am not interested in the datetime, but just the date portion of the it. So, after retrieving the date in Java, and excluding the hours, minutes, and seconds - I am left with "2012-06-14".
How can I convert this into UTC milliseconds?
EDIT: I'd missed the "ignoring the time of day" part. It's now present, but near the end...
The simplest approach is probably to use SimpleDateFormat, having set the time zone appropriately:
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = format.parse(text);
long millis = date.getTime();
(Setting the time zone is the important bit here, as otherwise it will interpret the value to be in the local time zone.)
Alternatively, if you're doing anything less trivial than this, use Joda Time which is a much better date/time API. In particular, SimpleDateFormat isn't thread-safe whereas DateTimeFormatter is:
// This can be reused freely across threads after construction.
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")
.withLocale(Locale.US)
.withZoneUTC();
// Option 1
DateTime datetime = formatter.parseDateTime(text);
long millis = dateTime.getMillis();
// Option 2, more direct, but harder to diagnose errors
long millis = formatter.parseMillis(text);
Now so far, we've parsed the whole whole caboodle. The easiest way of ignoring the date part is just to round it off - after all, Java doesn't observe leap seconds, so we can just truncate it:
long millisPerDay = 24L * 60L * 60L * 1000L; // Or use TimeUnit
long dayMillis = (millis / millisPerDay) * millisPerDay;
That will "round towards 1970" so if you have a date before 1970 it will round to the end of the day - but I suspect that's unlikely to be a problem.
With the Joda Time version you could just use this instead:
DateTime dateTime = formatter.parseDateTime(text);
long millis = dateTime.toLocalDate().getLocalMillis();
I would personally not go with the idea of just taking a substring. Even though you're not actually interested in preserving the hour/minute/second, I think it's appropriate to parse what you've been given and then throw away information. Aside from anything else, it makes your code fail appropriately with bad data, e.g.
"2012-06-100"
or
"2012-06-14 25:01:25"
indicate problems in whatever's supplying you data, and it's good to spot that rather than to continue blindly just because the first 10 characters are okay.
UPDATE: See the modern solution using java.time classes in the correct Answer by Ole V.V..
Simpler
The answer by Jon Skeet is correct. And he makes a good point about including, rather than truncating, the time-of-day info while parsing.
However, his code could be simplified. Especially so because Joda-Time gained an important new method in the latest versions: withTimeAtStartOfDay. This method supplants all the "midnight"-related classes and methods which are now deprecated.
Specifying a Locale is a good habit, as shown in his code. But in this particular case a Locale is not necessary.
His answer correctly suggests the Joda-Time library, far superior to using java.util.Date, .Calendar, and java.text.SimpleTextFormat. Those classes are notoriously troublesome, and should be avoided. Instead use either Joda-Time or the new java.time package built into Java 8 (inspired by Joda-Time, defined by JSR 310).
First Moment Of The Day
You cannot ignore time-of-day if what you want is a count of milliseconds-since-epoch. I suspect what you want is to change the time to first moment of the day. In UTC, this always means the time 00:00:00.000. But note that in local time zones, the first moment may be a different time because of Daylight Saving Time and possibly other anomalies.
ISO 8601
Your string is nearly in standard ISO 8601 format, but we need to swap a T for the SPACE in the middle. Then we can feed the resulting string directly to Joda-Time as Joda-Time has built-in formatters used by default for standard strings.
Example Code
The following example code assumes the intent of your question is to parse a string as a date-time value in UTC time zone, adjust the time to the first moment of the day, and then convert to number of milliseconds since Unix epoch (beginning of 1970 in UTC).
String inputRaw = "2012-06-14 05:01:25";
String input = inputRaw.replace( " ", "T" ); // Replace SPACE with a 'T'.
DateTime dateTime = new DateTime( input, DateTimeZone.UTC ); // Parse, assuming UTC.
DateTime dateTimeTopOfTheDay = dateTime.withTimeAtStartOfDay(); // Adjust to first moment of the day.
long millisecondsSinceUnixEpoch = dateTimeTopOfTheDay.getMillis(); // Convert to millis. Use a 'long', not an 'int'.
java.time and JDBC 4.2
I am providing the modern answer. These days (and for the last several years) you should use java.time, the modern Java date and time API, for your date and time work. And since JDBC 4.2 you can directly retrieve java.time objects from your database (and also store them into it). A modern JPA implementation (Hibernate at least since Hibernate 5) will be happy to do the same. So forget about SimpleDateFormat, Date and other old classes used in most of the old answers. The mentioned ones are poorly designed, and java.time is so much nicer to work with.
Retrieve proper date-time objects from your database
I also recommend that you don’t retrieve your UTC time as a string from the database. If the datatype in SQL is timestamp with time zone (recommended for UTC times), retrieve an OffsetDateTime. For example:
PreparedStatement pStmt = yourDatabaseConnection
.prepareStatement("select utc_time from your_table where id = 7;");
ResultSet rs = pStmt.executeQuery();
if (rs.next()) {
OffsetDateTime utcDateTime = rs.getObject("utc_time", OffsetDateTime.class);
long millisecondsSinceEpoch = utcDateTime.truncatedTo(ChronoUnit.DAYS)
.toInstant()
.toEpochMilli();
System.out.println("Milliseconds since the epoch: " + millisecondsSinceEpoch);
}
If the type in SQL is dateTime or timestamp without time zone, we probably need to retrieve a LocalDateTime instead (details depending on your JDBC driver and the time zone of your database session). It goes in the same manner. For converting your LocalDateTime to OffsetDateTime, see the conversion below.
If you need to convert from a string
If you cannot avoid getting your UTC time as a string as in the question, parse it into a LocalDateTime and convert from there. For example:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
String utcTimeString = "2012-06-14 05:01:25";
long millisecondsSinceEpoch = LocalDateTime.parse(utcTimeString, formatter)
.atOffset(ZoneOffset.UTC)
.toInstant()
.toEpochMilli();
System.out.println("Milliseconds since the epoch: " + millisecondsSinceEpoch);
Output:
Milliseconds since the epoch: 1339650085000
Link
Oracle tutorial: Date Time explaining how to use java.time.
Use the Date object in combination with SimpleDateFormat.
There is a method named getTime() in Date which will return the milliseconds for you.
Example that solves your problem :
Date truc = new SimpleDateFormat( "y-m-d").parse( "2010-06-14");
System.out.println(truc.getTime());
SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd"); //or whatever format you have
Date t = ft.parse('2014-03-20');
String result = String.format("%tQ", t);
System.out.printf("%tQ", t);
There are two methods here:
you put the result milliseconds into a variable result
printing it straight off.
I use a simple and straight forward approach:
Date date = new Date(utcDateInString);
long utcDateInMilliSeconds = date.getTime();