This question already has answers here:
java.text.ParseException: Unparseable date Error on using Clock.systemUTC() [duplicate]
(2 answers)
Closed 1 year ago.
The community reviewed whether to reopen this question 2 months ago and left it closed:
Original close reason(s) were not resolved
2024-01-01T00:00:00.000Z
I would like to get this String in ms(long)
I tried:
long res = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").parse(createdAt).getTime();
but it doesn't work.
java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Solution using java.time, the modern Date-Time API:
import java.time.Instant;
public class Main {
public static void main(String[] args) {
long res = Instant.parse("2024-01-01T00:00:00.000Z").toEpochMilli();
System.out.println(res);
}
}
Output:
1704067200000
ONLINE DEMO
Note that the modern Date-Time API is based on ISO 8601 and does not require using a DateTimeFormatter object explicitly as long as the Date-Time string conforms to the ISO 8601 standards.
Learn more about the modern Date-Time API from Trail: Date Time.
For any reason, if you want to use SimpleDateFormat:
Use the following format:
yyyy-MM-dd'T'HH:mm:ss.SSSXXX
Check the SimpleDateFormat documentation to understand the difference between Z and X.
* 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. Note that Android 8.0 Oreo already provides support for java.time.
Related
I am getting the strings like 1604341549 and want to convert them to normal date format like
12 feb 2012 4:00. Here is my implementation
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
try {
Date d = sdf.parse(date);
sdf.applyPattern("dd MMM yyyy hh:mm");
holder.v.setText(sdf.format(d));
} catch (ParseException ex) {
Log.e("Exception", ex.getLocalizedMessage());
}
I have checked the logs and it is showing the dates as String before the try block but it is not implementing in the try block instead it is giving an error " Unparseable date: "1604341549" ".
Looks like your date is a long that encodes timestamp in seconds so you don't need to parse a String, instead you should simply build a Date object using Date(long date) constructor. don't forget to convert seconds to milliseconds by multiplying it by 1000
java.time through desugaring
Consider using java.time, the modern Java date and time API, for your date and time work. Let’s first declare two formatters, one for your input and one for your desired output.
/** For parsing seconds since the epoch */
private static final DateTimeFormatter unixTimestampFormatter
= new DateTimeFormatterBuilder()
.appendValue(ChronoField.INSTANT_SECONDS)
.toFormatter();
/** For formatting into normal date and time */
private static final DateTimeFormatter normalFormatter
= DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
.withLocale(Locale.UK);
Now the conversion goes like this:
String inputStr = "1604341549";
Instant inst = unixTimestampFormatter.parse(inputStr, Instant.FROM);
String normalDateTimeStr = inst.atZone(ZoneId.systemDefault())
.format(normalFormatter);
System.out.println(normalDateTimeStr);
Output is:
02-Nov-2020 19:25:49
I am convinced that Shamm is correct in the other answer: your input strings contain so-called Unix timestamps, that is, counts of seconds since the Unix epoch on Jan 1, 1970 at 00:00 UTC. With java.time we can build a formatter that parses such.
For giving “normal” output I am using Java’s built-in date and time format. In this case for UK locale, but you should use your users’ locale for most content users.
What went wrong in your code?
First, you were trying to parse the input string as containing year, month, date, hour, etc., which it didn’t. So you were lucky to get an exception so you got aware that it’s wrong (SimpleDateFormat very often does not give that, leaving you believing that everything is fine when it isn’t).
SimpleDateFormat parsed 1604 as year, 34 as month, 15 as day of month and 49 as hour of day. It then objected because there weren’t any digits left for the minutes (and seconds).
Question: Doesn’t java.time require Android API level 26?
java.time works nicely on both older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On older Android either use desugaring or the Android edition of ThreeTen Backport. It’s called ThreeTenABP. In the latter case make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Unix time
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
Java 8+ APIs available through desugaring
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
I am Using Google APis .net client library to read calendar events.
I have following line of code
newRow["Start"] = pEventItem.Start.DateTime.HasValue ?
Convert.ToDateTime(pEventItem.Start.DateTime) : Convert.ToDateTime(pEventItem.Start.Date);
Where PEventItem is of type Google.Apis.Calendar.v3.Data.Event and NewRow[...] is of type DataRow. The Value of pEventItem.Start.Date is "2019-06-24" (as seen in debug window)
The above line of code works perfect, But fails when UI language / Culture is set to Arabic (SaudiArabia) The same Convert.ToDateTime throws error "String was not recognized as a valid DateTime".
btw, How i am changing the UI language is as below for your information.
Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.GetCultureInfo(ChangeLanguageTo);
Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo(ChangeLanguageTo);
I tried to set 2nd parameter of the Convert.ToDateTime function in an hope that it will convert date correctly...
CultureInfo enUsCulture = new CultureInfo("en-us");
newRow["Start"] = pEventItem.Start.DateTime.HasValue ? Convert.ToDateTime(pEventItem.Start.DateTime, enUsCulture) : Convert.ToDateTime(pEventItem.Start.Date, enUsCulture);
Well Now it does not throw exception, but the returned date is incorrect. value retuned is {21/10/40 12:00:00 ص}
while The actual date pEventItem.Start.Date is "2019-06-24"
I also tried invariant culture also, but result is same, converted date is wrong. What could be the issue?
Regards
There are a few things going on here.
Firstly, if you use EventDateTime.DateTime (e.g. via pEventItem.Start.DateTime) you don't need to call Convert.ToDateTime, because that's already a DateTime?... you can just take the Value property to get a DateTime from a DateTime?. However, I should warn that that can perform time zone conversions that you may not want. (We can't fix the library to avoid those, as it would be a breaking change.) Instead, you may want to parse EventDateTime.DateTimeRaw, which is the original string value returned by the API.
When parsing, I'd suggest using the invariant culture using CultureInfo.InvariantCulture (instead of creating an en-US culture), and parse using DateTime.ParseExact, specifying the format you expect based on whether you're parsing a date or a full date/time.
In terms of "the returned date is incorrect" - I believe that's really just the formatted value that's using the default culture, including the calendar system. We can see that at play in the code below, which constructs the DateTime directly (so can't be affected by any text parsing etc). When formatted using the invariant culture, it shows as 2019-06-24, but when formatted with ar-SA, it shows as "1440-10-21" due to the default calendar system for that culture being System.Globalization.UmAlQuraCalendar:
// Note: when a calendar system is not specified,
// it's implicitly Gregorian.
DateTime date = new DateTime(2019, 6, 24);
Console.WriteLine(date.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture));
Console.WriteLine(date.ToString("yyyy-MM-dd", new CultureInfo("ar-SA")));
So what you're seeing in the debugger is the correct date - but formatted in a way you weren't expecting.
I'm currently working on a Bot where users can ask to play a game and set when to play it:
.play Valorant #30 -> "#anyone_who_is_playing_valorant, up for a round in 30 minutes?"
Currently, I'm editing the message every minute to display the correct time left, which unfortunately makes implementing other commands and functions way more difficult as it should be (while loop etc).
My only solution would be to display the time at which 30 minutes would be passed:
Message written at 17:00 -> "#anyone_who_is_playing_valorant, up for a round at 17:30?"
but due to timezones the displayed timestring has to be different for each user.
Actually, Discord supports such a function for embeds, but I haven't found a standart support for sending dynamic timestrings. I would imagine it to be like Pings, where there is no function but a syntax for it: <#!authorid>
Is there a way to send dynamic timestrings?
There is no dynamic time syntax in Discord messaging, the only such functionality is the timestamp in embeds as you mentioned.
Actually there is a way to have a dynamic string in your message but it does not work for the footer in the embed.
You only need to make a unix code,
from datetime import datetime
import calendar
date = datetime.utcnow()
utc_time = calendar.timegm(date.utctimetuple())
print(utc_time)
your output looks something like this: 1657723929
You format the code to this: <t:unixcode:R>
and it gives you
7 minutes ago
You can also make a timestamp which leads to the future with just adding the secconds to the unix code you just made e.g.:
this code <t:2665824929:R> represents
in 32 years
depends on when you see this because its dynamic
Some requests to GitLab API, like listing Merge Requests (https://docs.gitlab.com/ee/api/merge_requests.html#list-merge-requests) allow for URL query parameters of datetime type (created_after and created_before params for this particular example).
I can't seem to find a format for the datetime param that would work. Timestamps (both with and without milliseconds) doesn't work, nor do the ISO format like 2017-06-29T11:00:00.000Z.
Maybe this query parameter doesn't work at all?
Found the reason: the created_before and created_after parameters, though listed and described in the official API documentation, are not yet included in any released version.
As of GitLab version 9.3.5 it's still listed under unreleased:
https://github.com/gitlabhq/gitlabhq/blob/master/changelogs/unreleased/12151-add-since-and-until-params-to-issuables.yml
https://github.com/gitlabhq/gitlabhq/commit/9fe6c2b2c2dd92831c93297021b41d6721e4b201
Try ISO8601 timestamps, therefore remove nanoseconds and include the timezone:
2017-06-29T11:00:00+00:00
Use for reference the ruby DateTime class as this one is used in Gitlab.
https://ruby-doc.org/stdlib-2.3.1/libdoc/date/rdoc/DateTime.html
The merge request API class of Gitlab:
https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/api/merge_requests.rb
This is the time format that worked for me (Standard ISO-8601):
three_weeks_ago = (datetime.datetime.now(timezone.utc)- timedelta(days=21)).isoformat() .
mrs = request(f'/merge_requests?state=merged&created_after={three_weeks_ago}&per_page=100')
In Gitlab 12.6.4-ee (Enterprise Edition), ISO8601 datetime formats like "2020-02-12T00:08:15Z" and "2020-02-12T00:07:15+01:00" work, when URL-encoded. So "2020-02-12T00:08:15Z" -> "2020-02-12T00%3A08%3A15Z", and "2020-02-12T00:07:15+01:00" -> "2020-02-12T00%3A07%3A15%2B01%3A00". So a full (fake) URL example would be: https://gitlab.mycompany.com/api/v4/projects/myproject/merge_requests?updated_after=2020-02-12T00%3A07%3A15%2B01%3A00
I got the time values from the SBT SDK as a string in this format
"2013-07-17T14:44:25.177Z"
I get a Java Date object with this code
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
Date date = dateFormat.parse("2013-07-17T14:44:25.177Z");
But the last part of the string ".177Z" should be a time zone value !?!?!
Do any body know how parse the time zone or the complete date with the time zone in Java?
Thx
Andreas
But the last part of the string ".177Z" should be a time zone value !?!?!
No, I think the .177 is the milliseconds part, and Z is a UTC-offset of 0. (It's not really a time zone, but that's a different matter.)
I suspect you want:
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
(Where X is an ISO-8601 time zone specifier, including Z for UTC.)
Note that X was only introduced in Java 7 - if you're using Java 6 or earlier, you may need to do a bit more work.
You might want to use
javax.xml.bind.DatatypeConverter.parseTime(String)
since the dates found in the atom returned by the IBM Connections API conform to the definition from http://www.w3.org/TR/xmlschema-2/, which can be parsed into a Java Calendar Object by said method. This also accounts for the time zone specifier.