ZonedDateTime: I would like parse() to fail on invalid date - datetime

I guess I just expected this to give me a parsing exception, but it didn't. I would like the parse to fail if the date is invalid. (That's what I need to know)
Added note: Using Feb. 30th as an invalid date: (In fact, what I need to do is receive five strings; year, month, day, hour, minute, which I assembly into str (below) and see if they come together as a valid date-time (in ZONE_ID).
String ZONE_NAME = "America/Los_Angeles";
ZoneId ZONE_ID = ZoneId.of(ZONE_NAME);
String ldtfPattern = "yyyy/MM/dd HH:mm";
DateTimeFormatter localDateTimeFormatter =
DateTimeFormatter.ofPattern(ldtfPattern);
String str = "2016/02/30 21:09";
try {
zdt = ZonedDateTime.parse(str, localDateTimeFormatter().withZone(ZONE_ID));
} catch(DateTimeParseException e) {
return null;
}
return zdt;
The string value of zdt after the parse above is
2016-02-29T21:09-08:00[America/Los_Angeles]

A little birdie told me to try using withResolverStyle() set to STRICT. With that, the only other trick I needed to make this work was to incorporate the era into my year. So the changes to the above are:
String ldtfPattern = "uuuu/MM/dd HH:mm";
and
zdt = ZonedDateTime.parse(str,
getLocalDateTimeFormatter().withZone(ZONE_ID).withResolverStyle(ResolverStyle.STRICT));
And this is working for me.

Related

Changing the Session Languge leads to "java.text.ParseException: Unparseable date

whenever I'm defining the timeframe being in German session language after changing to English lang. session (and vice versa) I'm getting the:
java.text.ParseException: Unparseable date: "10.10.2018"
Here is the fragment:
Date startDateFormatted = DateUtils.convertDateToMinusDayNumber(cal, dayRange);
Date endDateFormatted = new Date();
if (StringUtils.isNotEmpty(startDate) && StringUtils.isNotEmpty(endDate))
{
try
{
String datePattern = getLocalizedString("dd.MM.yyyy"); //
startDateFormatted = new SimpleDateFormat(datePattern).parse(startDate); // exception is throwing on this line
endDateFormatted = new SimpleDateFormat(datePattern).parse(endDate);
}
catch (final Exception e)
{
LOG.error(ERROR_DATE_PARSING, e);
}
}
java.time
I recommend you use java.time, the modern Java date and time API, for your date work.
String datePattern = "dd.MM.uuuu";
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(datePattern);
String startDateString = "10.10.2018";
LocalDate startDate = LocalDate.parse(startDateString, dateFormatter);
System.out.println(startDate);
Output:
2018-10-10
If you want to support different date formats for different locales, let Java handle that part for you:
String datePattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(
FormatStyle.MEDIUM, null, IsoChronology.INSTANCE, Locale.GERMAN);
German locale works with your example string of 10.10.2018. For UK locale, for example, a string like 10 Oct 2018 would be required instead, as Britons would typically expect.
What went wrong in your code?
We cannot tell from the information and code that you have provided exactly what happened. A couple of good guesses are:
As Arvind Kumar Avinash said in a comment, getLocalizedString() may be causing trouble. You may print datePattern to check. Localization is something you do to strings that you display to the user. Trying to localize a format pattern string for a formatter is probably plain wrong, so you should leave out that method call. That the error occurs when changing language seems to support this possibility.
There may be unexpected non-printing characters in your string. One way to check would be to print startDate.length(). If the length is greater than 10, there are more characters than the 10 chars in 10.10.2018.
Link
Oracle tutorial: Date Time explaining how to use java.time.

Using str2date with strings that also contain a time

I have a method which, given an .NET XmlNode containing an ISO 8601 date in the inner text, will convert it to an X++ date object.
if (CLRInterop::isInitialized(childNode))
{
return str2Date(childNode.innerText(), 321);
}
else return maxDate();
This works great if supplied a string which contains only a date (eg: 2019-03-21), but as soon as a time is also provided in this string (eg: 2019-03-21T00:00:00), it will return nothing.
The easiest fix for this would be just to strip everything past the first 10 characters, but this would break again if for some reason the string only contains 2 characters for the year. Is there a more robust way of handling strings including times in a call to str2date?
I just wrote this job with a bunch of examples. The very first line might be what you want. You can just create this as a new job in AX and then put a breakpoint on the first line and step through each to see what happens, or modify to experiment.
It looks like your string is standard ISO format, which I cover below various ways too.
static void DateTimeJob(Args _args)
{
// This line looks about what you want
utcDateTime utcDateTimeFromString = DateTimeUtil::anyToDateTime("2019-03-21T00:00:00");
// ISO standard format. You can just assign it directly without quotes
utcDateTime utcDateTimeISOFormat = 2019-03-21T00:00:00;
// Misc vars for below
utcDateTime utcNow;
System.DateTime systemDateTime;
date dateOnly;
str systemDateTimeStr;
// Look at
// DateTimeUtil::<> // This has all sorts of useful functions
// str2datetime() // May be useful to you
try
{
// How to go from AX UTC to System.DateTime
systemDateTime = Global::utcDateTime2SystemDateTime(DateTimeUtil::utcNow());
// How to go from System.DateTime to AX UTC
utcNow = Global::clrSystemDateTime2UtcDateTime(System.DateTime::get_UtcNow());
// How to get ONLY the date portion from a UTC
dateOnly = DateTimeUtil::date(utcNow);
// Cast to string for output
systemDateTimeStr = systemDateTime.ToString();
// Output a few examples
info(strFmt("%1, %2, %3",
systemDateTimeStr,
utcNow,
dateOnly));
}
catch (Exception::CLRError)
{
error(AifUtil::getClrErrorMessage());
}
}

Issue in converting Timespan variable to 12 hour format

I have a nullable variable Start time
Timespan? st=e.StartTime;//Null-able variable;
I am trying to get time in AM/PM format but I am unable to get it.
DateTime date = Convert.ToDateTime(st.ToString());
String f = String.Format("{0:hh:mm:tt}", date);
Error is:
System.FormatException: String was not recognized as a valid DateTime.
If you were to output the results of st.ToString(), you will find that it doesn't contain any date information, only hours, minutes and seconds.
This isn't a valid format for a DateTime, which generally contain date and time information.
You don't need to convert your TimeSpan to a DateTime to format it, you can just use TimeSpan.ToString():
string f = st.Value.ToString(#"hh\:mm\:tt");
For reference: http://msdn.microsoft.com/en-us/library/ee372287.aspx
Also, note the \ before the :, you must do this if you want to include literal strings in the output, as mentioned at the bottom of that documentation page.
Converting a timespan to a date is not possible, a timespan represents x amount of minutes/hours/whatever and you cannot get an exact date from that alone. If you have a date as a starting point, you can add a timespan and that will give you the new date.
st.ToString() will return "System.Nullable<Timespan>" because that is what a nullable type returns - it does not override the default Object.ToString implementation, so returns the type name.
If you want the string of the actual timespan, then you would need to do st.Value.ToString(), but you should be checking for null first (i.e. st.HasValue == true)
Edit: Also see #Sean's comment about how to output the Timespan without converting to a DateTime first.
Edit: Turns out I was slightly wrong - st.ToString() doesn't return the above. So see Sean's answer.
First convert Timespan to Datetime by adding TimeSpan to a base date of 00:00 hrs. Then on that dateTime derive the 12 hr format.
DateTime.Now.Date.Add(OpenTimeSpan).ToString(#"hh\:mm\:tt")
The Accepted Answer is wrong.
You cannot return AM/PM for a TimeSpan because it is only concerned with the length of Time,
not a Time of Day - hench the name, "TimeSpan".
Convert to a DateTime first before converting to a String:
string sTimeOfDay = new DateTime().Add(st).ToString("hh:mm tt");
Note: If your TimeSpan is nullable, then you will need to add Conditional Logic to Handle Nulls and pass in ts.Value instead of ts:
string sTimeOfDay = (st == null ? null : new DateTime().Add(st.value).ToString("hh:mm tt") );

asp.net c# - combine / format a date and time from separate sources

I'm parsing an XML file from an external source, and I have 2 attributes which contain the date and time respectively. I'm looking for the best way to get these into a format I can parse as a date so I can do things with it, but at the moment I'm just getting errors or no results with the methods I've tried.
The date is in the format "20111215" - which is yyyymmdd as it's UK based.
The time is formatted as "1417+0000" which I presume is the time plus offset from GMT?
Basically I need to get these into UK time. I've tried using DateTime.Parse on the separate parts but both give an error as not valid format. Tried String.Format on the date part but that didn't change it at all. I presume I need to combine the 2 before parsing but I'm not sure if I need to do anything else with it to make it acceptable.
Any help appreciated.
Use a DateTimeOffset to incorporate the timezone into the DateTime.
string date = "20111215";
string time = "1417+0500";
string dateAndTime = date + time;
string format = "yyyyMMddHHmmzzz";
CultureInfo provider = CultureInfo.InvariantCulture;
DateTimeOffset t = DateTimeOffset.ParseExact(dateAndTime, format, provider);
If you concatenate the fields together, you can then use DateTime.TryParseExact in order to parse them into a DateTime.
string input = string.Format("{0} {1}", dateString, timeString);
DateTime parsed;
if(DateTime.TryParseExact(input,
"yyyyMMdd HHmmK",
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out parsed))
{
// parsed OK, use the parsed variable
}
string date = "20111215";
string time = "1417+0000";
string dateString = date + time;;
string format = "yyyyMMddHHmmK";
// or something similar, I'm not sure about the timezone
DateTime result = DateTime.ParseExact(dateString,
format,
CultureInfo.InvariantCulture);
I think this should work (i didn't test it):
string dateString = "20111215";
string timeString = "1417+0000";
int year = int.Parse(dateString.Substring(0,4));
int month = int.Parse(dateString.Substring(4,2));
int day = int.Parse(dateString.Substring(6,2));
int hour = int.Parse(dateString.Substring(0,2));
int mins = int.Parse(dateString.Substring(2,2));
DateTime d = new DateTime(year, month, day, hour, mins, 0);

SQLite JDBC rs.getDate() getTimestamp() etc. all return wrong values

When using the JDBC for SQLite for some reason Date and Timestamp values are stored correctly in the DB, are displayed correctly when using the command line sqlite3 tool, but when using the ResultSet functions to retrieve these values it doesn't work. Below is a small test class that demonstrates what I mean.
import java.sql.*;
public class Test {
public static void main(String[] args) throws Exception {
Class.forName("org.sqlite.JDBC");
Connection conn = DriverManager.getConnection("jdbc:sqlite:test.db");
Statement stat = conn.createStatement();
stat.executeUpdate("drop table if exists people;");
stat.executeUpdate("create table people (name, occupation, date date);");
stat.executeUpdate("insert into people values ('Turing', 'Computers', date('now'));");
ResultSet rs = stat.executeQuery("select * from people;");
while (rs.next()) {
System.out.println("name = " + rs.getString("name"));
System.out.println("job = " + rs.getString("occupation"));
System.out.println("date = " + rs.getDate("date"));
System.out.println("dateAsString = " + rs.getString("date"));
}
rs.close();
conn.close();
}
}
The output I get is:
name = Turing
job = Computers
date = 1970-01-01
dateAsString = 2011-03-24
Like Scott says: SQLite does not have a Date type.
You could have SQLite do the conversion for you with the strftime function: strftime('%s', date). Then you can use rs.getDate on the Java side.
You can also retrieve the SQLite date as string, and parse that into a date:
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
try {
Date today = df.parse(rs.getString("date"));
System.out.println("Today = " + df.format(today));
} catch (ParseException e) {
e.printStackTrace();
}
SQLite3 does not have a Date type so you will have to get the String of the dates when writing your code.
http://www.sqlite.org/datatype3.html
SQLite does not use 'types' and instead uses what's known as 'type affinity';
From the documentation itself:
The important idea here is that the type is recommended, not required
You can store the dates as strings and parse them however you like with formatting classes like SimpleDateFormat or DateTimeFormatter, or you can use something crude like Date.from(Instant.parse(rs.getString("date"))).
Java 8
Amongst the other answers here, I'd say that LocalDate#parse() and LocalDateTime#parse() is also a good option for Java 8 moving forwards.
They accept a date in String format
LocalDate.parse("2016-05-24")
Or a String with a DateTimeFormatter as the second argument
LocalDate.parse("2016-05-24", DateTimeFormatter.ofPattern(yyyy-MM-dd))
Conversion
And if you're looking to use LocalDate or LocalDateTime but want to support Date, maybe in an adapter pattern;
LocalDateTime to Date:
This example uses the system default timezone as the ZoneId argument of atZone, however you can use a static/hard-coded timezone if you want to. Essentially you are creating an Instant from AtZone which can be used to build a Date from the static method Date#from(Instant)
Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
LocalDate To Date:
This example is pretty much the same, only here all that's required to get a ZoneId in order to create an Instant is the LocalDate instance itself.
Date.from(localDate.atZone(ZoneId.systemDefault()).toInstant()));
I've not gone into technical detail here, it may not even be necessary, but do correct me if I'm wrong.

Resources