Parsing date and time with the new java.time.DateTimeFormatter - parsing

I have a date of this type: 2004-12-31 23:00:00-08 but no one of the patterns i know and i have used from the documentation is working. I thought it should something like "yyyy-MM-dd HH:mm:ssX" but it isn't working.

Sorry for you, but this is a known bug and was already reported in January 2014. According to the bug log a possible solution is deferred.
A simple workaround avoiding alternative external libraries is text preprocessing. That means: Before you parse the text you just append the prefix ":00". Example:
String input = "2004-12-31 23:00:00-08";
String zero = ":00";
if (input.charAt(input.length() - 3) == ':') {
zero = "";
}
ZonedDateTime zdt =
ZonedDateTime.parse(
input + zero,
DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ssXXX"));
System.out.println(zdt);
// output: 2004-12-31T23:00-08:00
UPDATE due to debate with #Seelenvirtuose:
As long as you ONLY have offsets with just hours but without minute part then the pattern "uuuu-MM-dd HH:mm:ssX" will solve your problem, too (as #Seelenvirtuose has correctly stated in his comment).
But if you have to process a list of various strings with mixed offsets like "-08", "Z" or "+05:30" (latter is India standard time) then you should usually apply the pattern containing three XXX. But this currently fails (have verified it by testing in last version of Java-8). So in this case you still have to do text preprocessing and/or text analysis.

Related

Add custom localized text in DateTimeFormatter, for a new custom TemporalField

I've created a CENTURY field that implements java.time.temporal.TemporalField - this question is not focusing on the correct implementation details of such field (which will be handled later), I'm interested in the DateTimeFormatter issue as explained below.
Basically, the field gets the ChronoField.YEAR of a temporal object and uses this value to calculate the century (the calculation is made in getFrom(TemporalAccessor temporal) method, considering that the 1st century is from year 1 to 100 - but as I said, let's not stick too much in these details).
The most basic usage is:
LocalDate.of(2017, 1, 1).get(CENTURY); // 21
Which returns 21 in this case.
The field can also be used in a DateTimeFormatter:
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.appendPattern("dd/MM/yyyy ")
.appendValue(CENTURY)
.toFormatter();
System.out.println(fmt.format(LocalDate.of(2017, 1, 1))); // 01/01/2017 21
The output for the above is:
01/01/2017 21
But what I want to do is to use a custom localized text for this field. If I create a formatter like this:
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.appendPattern("dd/MM/yyyy ")
// century text
.appendText(CENTURY, TextStyle.SHORT)
// use English locale
.toFormatter(Locale.ENGLISH);
System.out.println(fmt.format(LocalDate.of(2017, 1, 1))); // 01/01/2017 21
Since there's no localized data for my new CENTURY field, the text is only its own value 21.
I'm trying to find a way to add custom localized strings for this field, like it's done with month and day of week, for example (let's assume that I already have the resource bundle properties files set).
Checking the source code, I've found that the formatter internally uses a TextPrinterParser, which in turn uses a DateTimeTextProvider to get the localized strings, but none of those classes are public and can't be used nor extended. And the API doesn't seem to provide a way to add custom localized strings for new fields.
I could do it only by using reflection and a java.lang.reflect.Proxy to overwrite the behaviour of the TextPrinterParser, but I wonder if there's a better way (that doesn't require all this "magic").
How can this be done (if possible)?
I know I could also use appendText(TemporalField field, Map<Long,String> textLookup), but that wouldn't be a "locale sensitive" solution (although it seems to be the best workaround available).
This is not possible in java.time.* today. The DateTimeTextProvider class was intended to be extensible, but this got descoped during development. Providing pluggable text providers would be a useful enhancement to Java.

Currency format is excelJS

How do you format currency in exceljs?
All I've found is this from their docs...which I have no clue how to type so I pasted it, but it doesn't seem to work
// Set Column 3 to Currency Format
ws.getColumn(3).numFmt = '�#,##0;[Red]-�#,##0';
Just took a little bit of tinkering with.
ws.getColumn(3).numFmt = '$#,##0.00;[Red]-$#,##0.00';
The #'s are optional digits. If you don't care about negative numbers being red you can leave it as $#,##0.00
For the full Accounting format, eg left-justified '$', $- for $0.00, etc, you can use:
const numFmtStr = '_("$"* #,##0.00_);_("$"* (#,##0.00);_("$"* "-"??_);_(#_)';
cell.numFmt = numFmtStr;
see: What are .NumberFormat Options In Excel VBA?

How to set the number of digits while printing in Java?

I couldn't really clarify what I'm asking in the title. I an integer for a day and a month. I have to print the month with a 0 in front of it if it's one digit only.
For example 04 if month = 4 and so on.
This is how it's supposed to look like in C#:
Console.WriteLine("{0}.{1:00}", day, month);
Thank you.
int month = 4;
DecimalFormat formater = new DecimalFormat("00");
String month_formated = formater.format(month);
Besides the answer Fernando Lahoz provided (which is pretty specific to your case: decimal formating) you can also use System.out.format in Java which allows you to specify a format-string while printing to System.out (the format function is applicable to any PrintStream though). In your case
System.out.format("%2d %2d", day, month)
should do the trick. The %dis used for decimal integers and you can then specify any width you want just before the 'd' (2 in your case).
If you want to access the string formed for later use and not (only) print it you can use String.format. It uses the same format as System.out.format but returns the String that is formed.
A complete syntax for all formats(string, decimal, floating point, calendar, date/time, ...) can be found here.
If you'd like a quick tuto on number-formatting you can check this link or this link instead.
Good luck!

How to parse a time value of type UTCTime from string in Haskell?

This is a follow-up question to the one I asked just a little while ago.
I couldn't find a single example (sorry for my Google skills) on the Haskell site which shows how to use the Data.Time functions to convert a formatted String to UTCTime and then be able to add/subtract minutes/seconds from that and convert back the UTCTime to formatted String.
I am looking for an example that shows how to convert a String (e.g. like "10:20:30" to UTCTime and then add 1000 seconds to that time. How to do this Haskell using the Data.Time library without using IO at all?
The type of the function should be FormatTime -> String -> UTCTime.
The function should use TimeLocale or FormatTime as locale/formatting is needed.
There are so many functions in the library and so many types that it just baffling. readTime, TimeLocale, ParseTime t, NominalDiffTime, Time and what not.
Please do not just point to docs on the Haskell site. Most of the docs there are just a dump of type signatures from the source code, without almost any examples. Sorry if this is coming as rant, but I have spent a lot of time trying to figure out something from those docs.
Compare this to Python docs on time. So many beautiful examples.
Thank god, there is SO.
import Data.Time
timeFormat = "%H:%M:%S"
understandTime = parseTimeOrError True defaultTimeLocale timeFormat
time :: UTCTime
time = understandTime "10:30:20"
λ> time
1970-01-01 10:30:20 UTC
Let's break down what's going on:
timeFormat is simply a string, describing how we expect the time to be passed to us.
we partially apply parseTimeOrError, using defaultTimeLocale for the locale, and previously defined timeFormat for the expected format.
We now have a understandTime function, that can take in a time as a String. When using it, we need to explicitly set the expected output type to UTCTime (this is what time :: UTCTime does). If we were to use understandTime within the context of a function that already expects a UTCTime, this would be unnecessary (for example addUTCTime 1000 (understandTime "10:30:20"))
We get back time. Note that the year, day, month and timezone default to 1970-01-01 and UTC because we do not explicitly read them in timeFormat.

Delphi require 4 digit year

A user will enter a string value for a date. StrToDate will be used to convert the string value to a DateTime. If the user enter's a date with a 2 digit year the date may be parsed as the current century (20xx) or the previous century (19xx).
To clear up any ambiguity, how do require the user enter a 4 digit year?
if isFourDigitYear(txbDate.Text) then
date := StrToDate(txbDate.Text)
else
ShowMessage('enter date with 4 digit year');
I think that the best choice would be to use TDateTimePicker
http://docwiki.embarcadero.com/Libraries/XE6/en/Vcl.ComCtrls.TDateTimePicker
If you are using older Delphi than Delphi 2009 with update pack 3 then you would wanna read next article to fix a bug found in TDateTimePicker.
http://www.tmssoftware.com/site/blog.asp?post=117
This bug has been fixed in newer versions.
Now if you are using FireMonkey take care about using TDateTimePicker as in Delphi XE3 it has a bug which srews up the date when entered through keyboard (can still be picked fine by mouse). I'm not sure if this was already fixed in later versions of Delphi or not.
If using of TDateTimePicker is out of the question then definitly use TMaskedEdit instead of regular TEdit since the chosen mask forces user to enter in text in proper format.
http://docwiki.embarcadero.com/CodeExamples/XE6/en/EditMask_(Delphi)
EDIT: The best advantage of using TDateTimePicker is that it automatically uses Date Time format that has been set on that specific system.
This means that date time format used will be the one user is used to. So there will be no mistakes in case if user local settings use dd/mm/yy format instead of mm/dd/yy.
One possibility is this:
FUNCTION IsFourDigitYear(DateStr : STRING ; DateSep : CHAR = '/') : BOOLEAN;
VAR
P : Cardinal;
BEGIN
DateStr:=DateStr+DateSep; Result:=TRUE;
REPEAT
P:=POS(DateSep,DateStr);
IF P=5 THEN EXIT;
DELETE(DateStr,1,P)
UNTIL DateStr='';
Result:=FALSE
END;
It will check that there is a part of the given string that has 4 characters.
It currently won't check if that part is numerical (ie. only contains digits). And it will require you to pass in the seperator character used if you want it to be truly international - there are some countries that use '-' as a date seperator, and most other countries in the world doesn't use the strange M/D/Y format, but either D/M/Y or Y/M/D format (where "/" may be "-" in some countries).
If you want a truly international function that also checks if the four-digit part is actually in the year part of the currently valid date format, then it'll need a much more complex parser. The above may get you started, however...

Resources