decimal number valued datetime formatting in 4gl - openedge

The value of the field is in (deci-5 99999999.99999) format, like:
20201231.65624
where 2020 is year, 12 is month, 31 is date and .65624 is the hour and minute value.
I want to display it like 31/12/2020 18:13.
I mean DD/MM/YY hh:mm like this format. So far, I am able to display only the date part i.e. 31/12/2020. But not able to display the hour and minute part.
Appreciate help on this regards. Thanks.

This will display the time portion in hh:mm:ss if the value is a string:
display string( integer ( entry( 2, "20201231.65624", "." )), "hh:mm:ss" ).
or, if the value is a decimal:
define variable d as decimal no-undo initial 20201231.65624.
display string( integer(( d - truncate( d, 0 )) * 100000 ), "hh:mm:ss" ).
Obviously you would want to abstract that approach to fit whatever your real need is.
The technique of using a character or decimal field to hold a datetime is a legacy of ancient versions of Progress that did not support a DATETIME or DATETIME-TZ datatype. Since OpenEdge 10 you have a native datatype that you should be using for that purpose. This kind of approach with decimals and strings should really only be used for backwards compatibility to old code and old database schemas.

Related

How to convert character type date to date type in SAS

I have a character variable in the form of "Jan-17" in my table and would like to convert it to date type. Does anyone what kind of date form this is and how I could go about converting it? Thank you.
SAS date variables are stored as number of days since Jan 1, 1960. For a variable that is Month and Year only, you'd need to pick a day - many choose the 1st, some the 15th or 30th/31st, depending on your business rules.
Either way, you can use the input function as a starting place. You need to know the informat - the instructions for how to translate characters to numbers. In your case, MONYY6. will likely work, though you can also try ANYDATEDTE. to let SAS guess the date informat to use.
Then, if needed, you can adjust the date it chose based on your business rules using the intnx function, which allows you to adjust it to the 15th or end of month if you prefer.
Use the INPUT() function with the correct informat.
data have;
date_char = 'Jan-17';
run;
data want;
set have;
date_dt = input(date_char, monyy6.);
format date_dt date9.;
run;
01JAN2017

Why 'T' is used in OffsetDateTime date format - java 8

I'm using OffsetDateTime class for parsing date from the database.
Why the date contains 'T' ??
Example: 2018-01-01T12:00:00.000Z
I can understand the format is <<Date>>T<<Time>>.<<Offset>><<TimeZone>>. But still, I don't understand why 'T' is used in between.
Thanks in advance
ISO 8601
2018-01-23T12:00:00.000Z
That means noon on the twenty-third of January in 2018 in UTC.
That is one of the standard formats defined by ISO 8601. These formats are designed for exchanging date-time values as text, easy to parse by machine, easy to read by humans across cultures. The ISO 8601 is a modern standard, supplanting formats seen in various earlier Internet standards. ISO 8601 is also being adopted in various industries beyond information technology.
The T in the middle separates the date portion from the time-of-day portion.
After the period (FULL STOP) is any number of digits for the fractional second. The standard prefers the use of COMMA, but people in the US often use the period.
The Z on the end is pronounced “Zulu” and means an offset-from-UTC of zero hours-minutes-seconds, or +00:00:00.
why 'T' is used in between
A letter was desired to avoid the use of SPACE characters to make recognition and parsing easier. As to why T, you’d have to ask the authors of the standard. I can only guess that the letter “t” was chosen for the word time in English, temps in French, etc.
The use of Z for an offset of zero is taken from common usage in aviation and military.
I highly recommend you use these ISO 8601 formats when storing, writing, exchanging, and logging date-time values as text. These formats are wisely designed to be simple and practical. They avoid the use of SPACE character, and avoid extensive use of English and any other language.
The java.time classes built into Java 8 and later use these formats by default when parsing and generating strings.
Instant.now().toString()
2019-08-27T20:15:21.005946Z
The java.time.ZonedDateTime class extends the standard wisely to append the name of the time zone in square brackets.
Instant instant = Instant.parse( "2019-08-27T20:15:21.005946Z" ) ;
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = instant.atZone( z ) ; // Same moment, same point on the timeline, different wall-clock time.
zdt.toString(): 2019-08-28T08:15:21.005946+12:00[Pacific/Auckland]
Week
You asked:
Am I able to use 'W' instead of 'T' in my given example
No. When representing a moment, you must use a T between the date and time.
A W is used in another of the ISO 8601 formats, when representing a week date of a week-based year.
String output = zdt.toLocalDate().format( DateTimeFormatter.ISO_WEEK_DATE ;
2019-W35-3
For working with standard weeks, use the YearWeek class from the ThreeTen-Extra project that extends java.time functionality.
LocalDate ld = zdt.toLocalDate() ;
YearWeek yw = YearWeek.from( ld ) ;
ld.toString(): 2019-08-28
yw.toSting(): 2019-W35
LocalDate ld = zdt.toLocalDate() ; // Extract just the date without the time-of-day and without time zone.
See all that code above run live at IdeOne.com, except for YearWeek.

SQLite select count records from 10 hours ago

I have this database
Table [Ticks]
Fields: 2
[Value]: INT
[Time]: DATETIME
Indexes: 1
[TicksIdx]
[Time]
[Value]
Triggers: 0
Table constraints:
Primary Key:
Fields:
On Conflict:
Foreign Keys: 0
Unique constraints: 0
Check constraints: 0
Table [Ticks] end
And I want to count all the records with value=-1 and Time < (Now-10 hours) from 10 hours ago until now
I have this query and always returns 0
select count(*) from Ticks where Value=-1 and
time>=datetime('now', '-10 hours')
If I change the query to this then it returns all the records
select count(*) from Ticks where Value=-1 and
time<datetime('now', '-10 hours')
and I have records with time values more recent than 10 hours
Explanations
You issue will be due to the value stored in the time column not being in a recognised format, complicated also with not comparing like for like.
The SQLite recognised formats can be found here SQL As Understood By SQLite - Date And Time Functions - Time Strings.
For example YYYY-MM-DD HH:MM:SS (e.g. 2018-12-09 12:40:01) is such a recognised format.
You query is (assuming 9/12/2018 12:40:01 AM from c# and the runtime is the same) saying:-
is 9/12/2018 12:40:01 AM >= 2018-12-09 12:40:01
as the values are non-numeric then a character by character comparison is undertaken so using these times 9 IS greater than 2 (of course if it were 09/12..... then IS NOT).
The correct way, to ensure like for like comparison, if the underlying data is in a recognised format, would be to ensure that both sides compare dimetime's as such really the SQL should therefore be :-
SELECT count(*) FROM Ticks WHERE Value=-1 AND datetime(time) >= datetime('now', '-10 hours')
note datetime(time) may only be needed if the date in the time column were another recognised format than the example format.
-note you may need to incorporate localtime to adjust times e.g. datetime(time) >= datetime('now','localtime', '-10 hours')
as per
The "localtime" modifier (12) assumes the time string to its left is
in Universal Coordinated Time (UTC) and adjusts the time string so
that it displays localtime. If "localtime" follows a time that is not
UTC, then the behavior is undefined. The "utc" modifier is the
opposite of "localtime". "utc" assumes that the string to its left is
in the local timezone and adjusts that string to be in UTC. If the
prior string is not in localtime, then the result of "utc" is
undefined.
Fix(es)
To fix the issue you would need to either
do a complex reformat of the time column, dependant upon the format of the value in the time column, for the comparison (not recommended)
or ensure that the value is stored in a SQlite recognised format.
If the time is the current time when the ticks row is inserted, then you could use time DATETIME DEFAULT CURRENT_TIMESTAMP as the definition for the time column and not supply a value for the time column when inserting a row.
Otherwise you should change the format of the value to a recognised format before storing the value.

How to compare two dates in SQLite?

I kind of assumed it was a string, so I compared it as a string, but not surprisingly it failed. I believe thats how it works in Mysql. I could be wrong as I haven't worked on it in a while. In either case, how can I check if dates are equal in SQLite? I will be using it in a WHERE clause.
SELECT a._id, b._id, b.start_date,a.event_name, b.start_time,
b.end_date, b.end_time, b.location FROM events_info b INNER JOIN events a ON
a._id=b.event_id WHERE b.start_time = '6:00';
(added space to make it easier to look at)
SQLite doesn't have a dedicated DATETIME type. Normally what people do is make sure they store the date as a formatted string that is consistent; for example, YYYY-MM-DD hh:mm:ss. If you do so, as long as you're consistent, then you can compare dates directly:
SELECT * FROM a WHERE q_date < '2013-01-01 00:00:00';
This works because even though the comparison is technically an alphabetical comparison and not a numeric one, dates in a consistent format like this sort alphabetically as well as numerically.
For such a schema, I would suggest storing dates in 24-hour format (the above example is midnight). Pad months, days, and hours with zeros. If your dates will span multiple timezones, store them all in UTC and do whatever conversion you need client-side to convert them to the local time zone.
Normally dates and times are stored all in one column. If you have to have them separated for whatever reason, just make sure you dates are all consistent and your times are all consistent. For example, dates should all be YYYY-MM-DD and times should all be hh:mm:ss.
The reason that YYYY-MM-DD hh:mm:ss is the preferred format is because when you go from the largest date interval (years) to the smallest (seconds), you can index and sort them very easily and with high performance.
SELECT * FROM a WHERE q_date = '2012-06-04 05:06:00';
would use the index to hone in on the date/time instead of having to do a full table scan. Or if they're in two separate rows:
SELECT * FROM a WHERE q_date = '2012-06-04' AND q_time = '05:06:00';
The key is to make sure that the dates and times are in a consistent format going into the database. For user-friendly presentation, do all conversion client-side, not in the database. (For example, convert '2012-06-04 05:06:00' to "1:06am Eastern 6/4/2012".)
If this doesn't answer question, could you please post the exact format that you're using to store your dates and times, and two example dates that you're trying to compare that aren't working the way you expect them to?
Sqlite can not compare dates directly. we need to convert them in seconds as well as integer also.
Example
SELECT * FROM Table
WHERE
CAST(strftime('%s', date_field) AS integer) <=CAST(strftime('%s', '2015-01-01') AS integer) ;
From Datatypes In SQLite Version 3:
1.2 Date and Time Datatype
SQLite does not have a storage class set aside for storing dates and/or times. Instead, the built-in Date And Time Functions of SQLite are capable of storing dates and times as TEXT, REAL, or INTEGER values:
TEXT as ISO8601 strings ("YYYY-MM-DD HH:MM:SS.SSS").
REAL as Julian day numbers, the number of days since noon in Greenwich on November 24, 4714 B.C. according to the proleptic Gregorian calendar.
INTEGER as Unix Time, the number of seconds since 1970-01-01 00:00:00 UTC.
Applications can chose to store dates and times in any of these formats and freely convert between formats using the built-in date and time functions.
If you look at the examples in Date And Time Functions, something like this should get you close to what you want (which, I'm assuming, is 6:00 of the current day):
WHERE b.start_time = date('now', 'start of day', '+6 hours')

C#: Convert AS/400 date into DateTime

Dates in DB2 AS/400 are an integer, containing the number of days since sometime around the turn of the 20th century.
Question 1: Does anyone know the IBM DB2/AS400 "zero" date? e.g.:
12/30/1899
12/31/1899
1/1/1900
Question 2: Given an "AS/400" date (e.g. 40010) how can you convert that to a CLR DateTime?
DateTime d = new DateTime(40010); //invalid
Some other "zero" dates are:
OLE Automation: 12/30/1899
SQL Server: 1/1/1900
I don't think AS/400 dates are stored internally as some number of days from an epoch date1 (this is the more common term for what you are calling "zero date"). As Tracy Probst said, this is definitely NOT what date fields in native AS/400 physical files look like.2
But that's immaterial if whatever method you are using to extract the data is giving it to you as the number of days since an epoch. Ideally, you should find out what the intended date is by looking directly at the AS/400, or asking someone who can. If the date on the AS/400 is 2009-07-30 and what you are getting is 40022, then you can be pretty confident the epoch date is Jan 1, 1900. If you are getting 40024, then the epoch is Dec 30, 1899. (Though it's of course best to compare a bunch of dates, preferably from different years to guard against possible use of Julian dates.)
Also, as Tracy commented on his own answer, it's exceedingly common for dates to be stored in generic numeric fields (which is what I would guess if your retrieval method is reporting Decimal as the data type), in which case it really has nothing to do with DB2's internal date format anyway. You should be aware that by far the most common date formats stored in AS/400 numeric fields are the following, or variations thereof:
yyyymmdd (Gregorian, ISO 4-digit year)
mmddyy (Gregorian, U.S. 2-digit year)
yyyyddd (so-called Julian, 4-digit year)
yyddd (so-called Julian, 2-digit year)
yymmdd
cyymmdd (IBM's crazy invention with century flag)
The ddd in the Julian dates is the number of days from the beginning of year. The c in IBM's crazy date is 0 for 19yy or 1 for 20yy. I have not heard of anyone who stores days-since-epoch on "The Four Hundred" but maybe you've encountered a convert from another platform. The mainframe heritage of the AS/400 strongly favors human-readable dates.
1The AS/400 (now called IBM i) does have its own data type for dates, and this data type actually does consist internally of a number of days from an epoch. But that epoch is many thousands of years in the past, not somewhere near the turn of the 20th century, and not even near the beginning of the Common Era. IBM likes to call this number of days the Scaliger number, but for most people who study this stuff, it's called the Julian Day Number. As you may have noticed from the main part of my answer, IBM uses the word "Julian" to mean something completely different (and not even related to the Julian calendar). Namely, IBM's so-called "Julian date" is really the ordinal date from ISO 8601.
2The internal format of the date data type is very low-level and mostly hidden from the user (including most programmers). The DSPPFM command, which ostensibly shows the "actual contents" of a file, is at least one step "too late": the value it reports has already been converted from the internal, 4-byte "Scaliger number" to a human-readable form.
Question 1:
I have no idea what the start date is for DB2. Google isn't very helpful anyway. Don't you have any sample data you could use to figure it out?
Update: are you sure the date is stored as a number of days? I found this page that suggests otherwise.
Question 2:
Assuming 1900-01-01 as the start date in this example, where days is the AS/400 date value.
DateTime myDate = new DateTime(1900, 1, 1).AddDays(days);
I don't know the answer for 1. But for 2, you can do something like this:
private DateTime AS400 = new DateTime(1900, 1, 1);
...
DateTime myClrDT = AS400.AddDays(days);
Question 1:
As far as I can tell, there is no "zero date" in an AS/400 phsyical file. If I do a DSPPFM on a phsyical file with a timestamp field in it, the value is stored as a readable timestamp in the format yyyy-MM-ddhh.mm.ss. For example: "2005-08-0207.06.33" for 08/02/2005 at 7:06:33 AM. There can be a zero-date within a particular programming language and that's really where you need to focus. The AS/400 ODBC driver returns the date in a SQL_TYPE_TIMESTAMP field.
Question 2:
It should be as simple as:
DateTime d = Convert.ToDateTime(reader["DateField"]);
I invite other C# experts to edit the response with better C# code.
I've just 5 months of experience in DB2(working on AS400), so i just can show you something
about the way we work with dates. It's true that we consider the 'zero' date in our calculation of the date fields. In our system, the 'zero' date =12/31/1971 0:00.
I don't know if this is the 'only' 'zero' date in AS400.
In our system files, the date we use is stored as the number of days from the 'zero' date(length=5).
So, every time we have to get the date field, from a specified file, we convert this field to get the date in the format : dd/mm/yyyy or yyyy-mm-dd(it depends from the environment where we execute the query). The function is:
date(field+719892), where field is the field where we store the date and 719892 is the number of days we add after each unconverted date we use(it seems like it is the number of days between x-12/31/1971, you can calculate x).
I'll give you on more example:
select date(15+719892) as date1 from library1.file1
The result is: date1=1972-01-15
marc_s had a comment that confused the "zero" dates with "minimum" dates in SQL Server. Just so everyone gets to see the example:
SELECT
CAST(0 AS datetime) AS dateTimeZero,
CAST(0 AS smalldatetime) AS smallDateTimeZero
dateTimeZero smallDateTimeZero
======================= ===================
1900-01-01 00:00:00.000 1900-01-01 00:00:00

Resources