Delphi require 4 digit year - delphi

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...

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.

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!

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

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.

How to convert to TDateTime an string formatted this way: 15h44m28s? [duplicate]

This question already has answers here:
Converting a string to TDateTime based on an arbitrary format
(8 answers)
Closed 9 years ago.
I have file names encoded with datetimes in the format:yyyy-mm-dd_HHhMMhSSs.
Real example: 2013-08-05_15h44m28s (in the time portion, it can have only the hour part)
I have to convert it back to an actual datetime. The date part is so easy that it's already solved, but for the time portion I didn't found in my delphi install a way to do that out-of-the-box.
So I got an SScanf implementation to solve that, but the question remains: did I overlook something or it's indeed the way to do that without having to write code myself?
Note: although I tagged my delphi version, functions that exist in more recent versions are interesting too.
BTW, someone knows if that formatting of the time portion have an name?
This is a good use case for a regex. Once you pulled off the date then you can use this regex:
(\d+)h(\d+)m(\d+)s
In fact, you may as well parse the entire string that way. All you need is this function:
function ToDateTime(const str: string): TDateTime;
var
Match: TMatch;
begin
Match := TRegEx.Match(str, '(\d+)-(\d+)-(\d+)_(\d+)h(\d+)m(\d+)s');
if Match.Groups.Count<>7 then
raise Exception.CreateFmt('Could not parse date/time: %s', [str]);
Result := EncodeDateTime(
StrToInt(Match.Groups[1].Value),
StrToInt(Match.Groups[2].Value),
StrToInt(Match.Groups[3].Value),
StrToInt(Match.Groups[4].Value),
StrToInt(Match.Groups[5].Value),
StrToInt(Match.Groups[6].Value),
0
);
end;

Convert WideString to String

How can I replace the empty widestring characters from a string?
e.g:
'H e l l o' convert to 'Hello'
I read an text blob field from a DB, and want to store it in another table. When I read it, I get the extra spaces, when I store it the extra spaces remains, and cannot be read correctly at the next query.
DXE, Firebird 2.5
UPDATE:
I use the IBQuery -> DataSetProvider -> ClientDataSet without desin-time created fields.
It seams, that the IBQuery retrieves the data in that wrong format.
Current Write Code:
blobStream := TStringStream.Create;
...
blobStream.WriteString(blobText); //blobText = 'H e l l o';
ibsql.ParamByName('ABLOBCOL').LoadFromStream(blobStream);
...
ibsql.ExecQuery;
...
In the FB database is 'H e l l o' stored, but it must be 'Hello'. Since it seems to be a bug in IBQuery, I need a way to convert that string.
First of all, I'm not going to attempt to describe how to remove every other character from a string. Whilst that might appear to solve your problem it merely papers thinly over the gaping cracks. What you have here is a classic text encoding mismatch. The real solution to your problem will involve fixing the mismatch.
I suspect the problem arises in code that you have not shown. As I understand your question now, you have a string variable blobText that contains incorrectly encoded text. But the code in the question takes blobText as input, and so the damage has already been done by the time we reach the code in the question. The key to solving this is the code that puts duff data into blobText.
You need to find the code which assigns to blobText and sort out the encoding problem there. It looks like you have taken UTF-16 encoded text and interpreted it as if it had an 8 bit encoding. I could speculate as to how that would happen, but it would be better for you to look at the actual code, the code that assigns to blobText. If you cannot work it out, please do post an update to the question.
I'm pretty confident that there are no bugs in the database libraries and that this is just an encoding mismatch.

Resources