What is the difference between Informix `%iY` and `%Y` format - informix

I found in some code I maintain they used this format for an update query
UPDATE X=to_date('$var','%iY-%m-%d %H:%M:%S.%F3') ...
But I can't find anywhere in Informix documentation what the i is for. Running this next query will result the same values.
SELECT TO_CHAR(CURRENT, '%Y-%m-%d %H:%M:%S%F3') as wo_I,
TO_CHAR(CURRENT, '%iY-%m-%d %H:%M:%S%F3') as with_I FROM X;
wo_i | with_i
------------------------|------------------------
2017-06-20 16:49:44.712 | 2017-06-20 16:49:44.712
So what am I missing?
Resources I looked into:
https://www.ibm.com/support/knowledgecenter/SSGU8G_11.70.0/com.ibm.sqlt.doc/ids_sqt_130.htm
https://www.ibm.com/support/knowledgecenter/SSGU8G_11.70.0/com.ibm.sqlt.doc/ids_sqt_129.htm
http://www.sqlines.com/informix-to-oracle/to_char_datetime

It's a trifle hard to find, but one location for the information you need (assuming you use Informix 11.70 rather than 12.10, though it probably hasn't changed much) is:
Client APIs and Tools — GLS User's Guide — GLS Environment Variables
In particular, it says:
%iy — Is replaced by the year as a two-digit number (00 - 99) for both reading and printing. It is the formatting directive specific to IBM Informix for %y.
%iY — Is replaced by the year as a four-digit number (0000 - 9999) for both reading and printing. It is the formatting directive specific to IBM Informix for %Y.
…
%y — Requires that the year is a two-digit number (00 through 99) for both reading and printing.
%Y — Requires that the year is a four-digit number (0000 through 9999) for both reading and printing.
There clearly isn't much difference between the two — I'm not even sure I understand what the difference is supposed to be. I think it may be the difference between accepting but not requiring leading zeros on 1, 2 or 3 digit year numbers. But for the most part, it seems you can treat them as equivalent.

Related

Rails: Get timezone offset name

In Ruby or Rails, given a timezone identifier like America/Los_Angeles, I see how I can get the specific timezone offset abbreviation like PDT:
Time.current.in_time_zone('America/Los_Angeles').zone
=> "PDT"
Time.now.in_time_zone("America/Los_Angeles").strftime('%Z')
=> "PDT"
Time.now.in_time_zone("America/Los_Angeles").strftime('%z')
=> "-0700"
And even a friendly name for the timezone itself:
ActiveSupport::TimeZone::MAPPING.key('America/Los_Angeles')
=> "Pacific Time (US & Canada)"
But how can I get a string like Pacific Daylight Time instead of just PDT to represent the full timezone offset name for a specific date?
Input: America/Los_Angeles and a specific date or datetime
Desired Output: Pacific Daylight Time
Short story: ~for some reason,~ (as #bata mentioned in his answer the abbreviations are not unique so this might be a reason for no official abbreviation-human friendly name mapping) The standard seems not to support it. You might need to implement this mapping yourself. But read on if you want to get some pointers why it might not be that easy.
So... this was an interesting rabbit hole to fall into...
Which gems are used and where do they get the info from
ActiveSupport uses tzinfo gem for that which in turn uses tz-info gem. tz-info says it uses one of two data sources:
zoneinfo directory in the Unix like system
TZInfo::Data
Rails' Gemfile template confirms that TZInfo data is used on window
At first I thought there might be a PR opportunity to contribute to a popular gem. Quick search suggests that there's no mapping of PDT to any "human friendly form".
Looking at unix's zoneinfo database
$ cat /usr/share/zoneinfo/America/Los_Angeles
TZif2H*ˉ#pa&t\؀Ðݩ޾߉iip~KIR^-)4GJQ',3qo_O?/v( fe HG *)
x
q(a'Q
A 0C ΐ
௠
#j$5 %J& '*'))6 "S 54+ !"V
eGYe턠g';gfiiHjke lmvG noV) pq6: XX YZ [޵\ ]^d _y`Mޠab-cgwdE G-Gӵ I
ros tOt v8vxx͠yz{f|~}H~^s*&
LMTPDTPSTPWTPPTTZif2^H*ˉ#pa&t\؀Ðݩ޾߉iip~KIR^-)4GJQ',3qo_O?/v( fe HG *)
x
q(a'Q
A 0C ΐ
௠
#j$5 %J& '*'))6 "S 54+ !"V
eGYe턠g';gfiiHjke lmvG noV) pq6: XX YZ [޵\ ]^d _y`Mޠab-cgwdE G-Gӵ I
ros tOt v8vxx͠yz{f|~}H~^s*&
LMTPDTPSTPWTPPT
PST8PDT,M3.2.0,M11.1.0
Looks like a binary file...
$ strings /usr/share/zoneinfo/America/Los_Angeles
TZif2
v+ !
2s$
3Gt 4S
5'V 62
mvG n
oV) p
TZif2
v+
3Gt
5'V
mvG
oV)
PST8PDT,M3.2.0,M11.1.0
Hmm. Whatever each of those means, there seems to be no "human friendly" name for this TZ.
More digging for unix tzinfo format, and there's apparently a zic and zdump tool
$ zdump /usr/share/zoneinfo/America/Los_Angeles
/usr/share/zoneinfo/America/Los_Angeles Thu Sep 10 03:07:49 2020 PDT
Not very useful...
$ zic /usr/share/zoneinfo/America/Los_Angeles
"/usr/share/zoneinfo/America/Los_Angeles", line 1: line too long
Ugh.
But reading the manpages for one of those tools I've found out that timezoneinfo is an official RFC 8536. I'm not great at reading those, but in the format there's header (with version only) and
data block (check it out, apparently it stores all historical changes for the TZ)
footer which seems to contain the PDT strings and alike, and nowhere is mentioned a possibility to provide "friendly" name.
If you have hard times reading an RFC, it looks like the tzinfo-data gem tries to reproduce the same data for system that does not include tzinfo databases (i.e. Windows):
https://github.com/tzinfo/tzinfo-data/blob/4ab39f022f5537b97eed133c1169f9ace3a82e2b/lib/tzinfo/data/definitions/PST8PDT.rb
timezone 'America/Los_Angeles' do |tz|
tz.offset :o0, -28378, 0, :LMT
tz.offset :o1, -28800, 0, :PST
tz.offset :o2, -28800, 3600, :PDT
tz.offset :o3, -28800, 3600, :PWT
tz.offset :o4, -28800, 3600, :PPT
tz.transition 1883, 11, :o1, -2717640000, 7227400, 3
tz.transition 1918, 3, :o2, -1633269600, 29060207, 12
tz.transition 1918, 10, :o1, -1615129200, 19375151, 8
tz.transition 1919, 3, :o2, -1601820000, 29064575, 12
tz.transition 1919, 10, :o1, -1583679600, 19378063, 8
tz.transition 1942, 2, :o3, -880207200, 29164799, 12
# ... [cut!]
Here's offset method definition: https://github.com/tzinfo/tzinfo/blob/f361d7d0b859ba5b91d30ffd6b66c3c59f90e969/lib/tzinfo/format2/timezone_definer.rb#L37:L59 (at least I think this is it, you never know until you run the code in ruby)
As you can see, no daylight saving time has :LMT and :PST abbreviations.
And here is the transition method https://github.com/tzinfo/tzinfo/blob/8c549373736a7873e18bb787b818d8786591e5e5/lib/tzinfo/format1/timezone_definer.rb#L30:L61
Feel free to explore more on your own. But it looks like each and every one transition from DST and back is supposed to be present in the tzinfo. And LA seems to have stuff planned until 2060. That's actually interesting if you'll get TZ bugs related to DST if you try to calculate times after 2060?
Last thing: Abbreviations
No idea if this is the case for unix's tzinfo db, but in the gem they are defined locally!
It seems to be the case that :PDT means the same if all definitions (https://github.com/tzinfo/tzinfo-data/search?q=%3APDT&unscoped_q=%3APDT)
But notice that
lib/tzinfo/data/definitions/Asia/Manila.rb defines positive offset tz.offset :o3, 28800, 3600, :PDT, but
lib/tzinfo/data/definitions/America/Dawson.rb defines negative offset tz.offset :o7, -28800, 3600, :PDT with the same abbreviation.
What does that mean - no idea. But that might be the reason we don't have "global friendly timezone names" anywhere.
There might be errors in the database. The official DB README says:
This database of historical local time information has several goals:
Provide a compendium of data about the history of civil time that
is useful even if not 100% accurate.
Give an idea of the variety of local time rules that have existed
in the past and thus may be expected in the future.
Test the generality of the local time rule description system.
The information in the time zone data files is by no means authoritative;
fixes and enhancements are welcome. Please see the file CONTRIBUTING
for details.
I don’t think there is a standard for abbreviations. Also, they are not unique as you see here: https://www.timeanddate.com/time/zones/

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!

ruby/rails detect financial track data and return nil/empty string

I read through similar stackoverflow questions to understand financial track card data.
I think the issue I am facing might be slightly different or maybe I am really weak in regex.
Now we have a service that returns track data accidentally instead of the guest name.
My goal is every time I receive track data I display "" empty string, else return the guest name.( This is a temp solution until we fix the root cause)
This is what my regular expressions is but looks like it doesn't detect track data.
irb(main):043:0> guestname="%4234242xx12^TEST/GUEST L ^324532635645744646462"
irb(main):044:0> (/[(%[bB])(;)]\d{3,}.{9,}[(^.+^)(=)].+\?.{,2}/.match(guestname)) ? "" : guestname
=> "%4234242xx12^TEST/GUEST L ^324532635645744646462"
(Not real data)
Now, looking at the wiki for track data information I want to cover most cases, if not all:
https://en.wikipedia.org/wiki/Magnetic_stripe_card#Financial_cards
Could some help with my regex. This is what I have:
/[(%[bB])(;)]\d{3,}.{9,}[(^.+^)(=)].+\?.{,2}/
Track 1, Format B:
Start sentinel — one character (generally '%')
Format code="B" — one character (alpha only)
Primary account number (PAN) — up to 19 characters. Usually, but not
always, matches the credit card number printed on the front of the
card.
Field Separator — one character (generally '^')
Name — 2 to 26 characters
Field Separator — one character (generally '^')
Expiration date — four characters in the form YYMM.
Service code — three characters
Discretionary data — may include Pin Verification Key Indicator (PVKI,
1 character), PIN Verification Value (PVV, 4 characters), Card
Verification Value or Card Verification Code (CVV or CVC, 3
characters)
End sentinel — one character (generally '?')
Longitudinal redundancy check (LRC) — it is one character and a
validity character calculated from other data on the track.
Track 2: This format was developed by the banking industry (ABA). This
track is written with a 5-bit scheme (4 data bits + 1 parity), which
allows for sixteen possible characters, which are the numbers 0-9,
plus the six characters : ; < = > ? . The selection of six
punctuation symbols may seem odd, but in fact the sixteen codes simply
map to the ASCII range 0x30 through 0x3f, which defines ten digit
characters plus those six symbols. The data format is as follows:
Start sentinel — one character (generally ';')
Primary account number (PAN) — up to 19 characters. Usually, but not
always, matches the credit card number printed on the front of the
card.
Separator — one char (generally '=')
Expiration date — four characters in the form YYMM.
Service code — three digits. The first digit specifies the interchange
rules, the second specifies authorisation processing and the third
specifies the range of services
Discretionary data — as in track one
End sentinel — one character (generally '?')
Longitudinal redundancy check (LRC) — it is one character and a
validity character calculated from other data on the track. Most
reader devices do not return this value when the card is swiped to the
presentation layer, and use it only to verify the input internally to
the reader.
Your example input string does not contain format code after first sentinel.
You are trying to parse html-encoded version, which is weird.
So, I would start with html decoding. E.g. with Nokogiri:
▶ guestname="%4234242xx12^TEST/GUEST L ^324532635645744646462"
#⇒ "%4234242xx12^TEST/GUEST L ^324532635645744646462"
▶ parsed = Nokogiri::HTML.parse(guestname).text
#⇒ "%4234242xx12^TEST/GUEST L ^324532635645744646462"
OK, now we at least have a leading percent. Now let us ask ourselves: how many users have a guest name starting with a percent sign? I bet none. You might re-check yourself by running a query against your database. Since it is a temporary solution, I would definitely shut the perfectionism up and go with:
▶ parsed =~ /\A%/ ? '' : parsed
Hope it helps.

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.

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