I finish devel. of Oracle compatible DateTime routines TO_CHAR(),

TO_DATE()
and PgSQL extension FROM_CHAR().

TO_CHAR() routine allow formating text output with a datetime values:

        SELECT TO_CHAR('now'::datetime, '"Now is: "HH24:MI:SS');
        to_char
        ----------------
        Now is: 21:04:10

FROM_CHAR() routine allow convert text to a datetime:

        SELECT FROM_CHAR('September 1999 10:20:30', 'FMMonth YYYY
HH:MI:SS');
        from_char
        -----------------------------
        Wed Sep 01 10:20:30 1999 CEST

TO_DATE() is equal with FROM_CHAR(), but output a Date only:

        SELECT TO_DATE('September 1999 10:20:30', 'FMMonth YYYY
HH:MI:SS');
        to_date
        ----------
        09-01-1999


In attache is compressed dir for the contrib. All is prepared, but I'am
not
sure if Makefile is good (probably yes).

Comments & suggestions ?


Thomas, thank you for your good advices.

                                                        Karel


------------------------------------------------------------------------------

Karel Zak <zakkr@zf.jcu.cz>
http://home.zf.jcu.cz/~zakkr/
This commit is contained in:
Bruce Momjian 1999-11-29 23:26:18 +00:00
parent 1f747c6722
commit 1c5aec60bb
10 changed files with 1878 additions and 0 deletions

View File

@ -10,6 +10,14 @@ array -
Array iterator functions
by Massimo Dal Zotto <dz@cs.unitn.it>
bit -
Bit type
by Adriaan Joubert <a.joubert@albourne.com>
dateformat -
Date Formatting to/from character strings
by Karel Zak - Zakkr <zakkr@zf.jcu.cz>
datetime -
Date & time functions
by Massimo Dal Zotto <dz@cs.unitn.it>

View File

@ -0,0 +1,71 @@
#-------------------------------------------------------------------------
#
# Makefile --
#
# Makefile for TO-FROM_CHAR module.
#
#-------------------------------------------------------------------------
PGDIR = ../..
SRCDIR = $(PGDIR)/src
include $(SRCDIR)/Makefile.global
INCLUDE_OPT = -I ./ \
-I $(SRCDIR)/ \
-I $(SRCDIR)/include \
-I $(SRCDIR)/port/$(PORTNAME)
CFLAGS += $(INCLUDE_OPT) $(CFLAGS_SL)
MODNAME = to-from_char
SQLDEFS = $(MODNAME).sql
MODULE = $(MODNAME)$(DLSUFFIX)
MODDIR = $(LIBDIR)/modules
SQLDIR = $(LIBDIR)/sql
all: module sql
module: $(MODULE)
sql: $(SQLDEFS)
install: $(MODULE) $(SQLDEFS) $(MODDIR) $(SQLDIR)
cp -p $(MODULE) $(MODDIR)/
strip $(MODDIR)/$(MODULE)
cp -p $(SQLDEFS) $(SQLDIR)/
install-doc:
if [ -d "$(DOCDIR)" ]; then \
cp -p *.doc $(DOCDIR); \
else \
cp -p *.doc $(SQLDIR); \
fi
$(MODDIR):
mkdir -p $@
$(SQLDIR):
mkdir -p $@
%.sql: %.sql.in
sed "s|MODULE_PATHNAME|$(MODDIR)/$(MODULE)|" < $< > $@
.SUFFIXES: $(DLSUFFIX)
%$(DLSUFFIX): %.c
$(CC) $(CFLAGS) -shared -o $@ $<
depend dep:
$(CC) -MM $(INCLUDE_OPT) *.c >depend
clean:
rm -f *~ $(MODULE) $(MODNAME).sql
ifeq (depend,$(wildcard depend))
include depend
endif

View File

@ -0,0 +1,25 @@
PROGRAM = rand_datetime
OBJECTS = rand_datetime.o
CFLAGS = -Wall -fpic -O3
CC = gcc
RM = rm -f
LIBS =
INCLUDE =
COMPILE = $(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDE)
LINK = $(CC) $(CFLAGS) -o $@ $(LIBS)
all: $(PROGRAM)
$(PROGRAM): $(OBJECTS)
$(LINK) $(OBJECTS)
.c.o: $<
$(COMPILE) -c $<
clean:
$(RM) -f *~ $(OBJECTS) $(PROGRAM)

View File

@ -0,0 +1,33 @@
TO/FROM CHAR tests
~~~~~~~~~~~~~~~~~~
* rand_datetime
The program 'rand_datetime' output a random datetime strings
(with yaer range 0..9999), you can use this for datetime testing.
You can usage this (example) for table filling.
Usage:
./rand_datetime <randfile> <num> <prefix> <postfix>
Example:
./rand_datetime /dev/urandom 2 "INSERT INTO tab VALUES('" "'::datetime);"
INSERT INTO tab VALUES('Sat 27 Jul 13:08:57 19618'::datetime);
INSERT INTO tab VALUES('Wed 25 Aug 20:31:50 27450'::datetime);
* regress
psql < regress.sql (all answers, must be TRUE, for Posgres
datestyle)
--> TO_DATE() is simular as FROM_CHAR(), but convert full datetime
to date ==> needn't test (?).

View File

@ -0,0 +1,71 @@
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
char *month[] = {
"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec",NULL
};
char *day[] = { "Sun","Mon","Tue","Wed","Thu","Fri","Sat", NULL };
int num(FILE *f, int min, int max)
{
int x, y, one;
one = x = fgetc(f);
if (x < min)
x = min;
else if (x > max) {
while(x > max)
x /= 2;
return x;
}
do {
y = fgetc(f);
if ((x+y) > max)
return x;
x += y;
} while(--one > 0);
return x;
}
int main(int argc, char **argv)
{
FILE *f;
int count;
if (argc < 5) {
printf("\nUsage: %s <randfile> <num> <prefix> <postfix>\n", argv[0]);
printf("\n(C) Karel Zak - Zakkr 1999\n\n");
exit(1);
}
if ((f = fopen(argv[1], "r")) == NULL) {
perror(argv[1]);
exit(1);
}
count = atoi(argv[2]);
for(; count > 0; --count) {
fprintf(stdout, "%s%s %02d %s %02d:%02d:%02d %d%s\n",
argv[3],
day[ num(f, 0, 6) ],
num(f, 1, 28),
month[ num(f, 0, 11) ],
num(f, 0, 23),
num(f, 0, 59),
num(f, 0, 59),
num(f, 0, 9999),
argv[4]
);
}
exit(0);
}

View File

@ -0,0 +1,58 @@
---
--- Postgres DateStyle needs all tests which parsing 'now'::datetime string
---
SET DATESTYLE TO 'Postgres';
SELECT 'now'::datetime =
TO_CHAR('now'::datetime, 'Dy Mon DD HH24:MI:SS YYYY')::datetime
as "Now vs. to_char";
SELECT 'now'::datetime =
FROM_CHAR('now'::datetime, 'Dy Mon DD HH24:MI:SS YYYY')
as "Now vs. from_char";
SELECT FROM_CHAR('now'::datetime, 'Dy Mon DD HH24:MI:SS YYYY') =
TO_CHAR('now'::datetime, 'Dy Mon DD HH24:MI:SS YYYY')::datetime
as "From_char vs. To_char";
SELECT 'now'::datetime =
FROM_CHAR(
TO_CHAR('now'::datetime, '"Time: "HH24-MI-SS" Date: "Dy DD Mon YYYY'),
'"Time: "HH24-MI-SS" Date: "Dy DD Mon YYYY'
)
as "High from/to char test";
SELECT TO_CHAR('now'::datetime, 'SSSS')::int =
TO_CHAR('now'::datetime, 'HH24')::int * 3600 +
TO_CHAR('now'::datetime, 'MI')::int * 60 +
TO_CHAR('now'::datetime, 'SS')::int
as "SSSS test";
SELECT TO_CHAR('now'::datetime, 'WW')::int =
(TO_CHAR('now'::datetime, 'DDD')::int -
TO_CHAR('now'::datetime, 'D')::int + 7) / 7
as "Week test";
SELECT TO_CHAR('now'::datetime, 'Q')::int =
TO_CHAR('now'::datetime, 'MM')::int / 3 + 1
as "Quartal test";
SELECT TO_CHAR('now'::datetime, 'DDD')::int =
(TO_CHAR('now'::datetime, 'WW')::int * 7) -
(7 - TO_CHAR('now'::datetime, 'D')::int) +
(7 - TO_CHAR(('01-Jan-'||
TO_CHAR('now'::datetime,'YYYY'))::datetime,'D')::int)
+1
as "Week and day test";

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,183 @@
TO_CHAR(datetime, text)
-----------------------
(returns text)
TO_CHAR - the DateTime function for formating date and time outputs.
This routine is inspire with the Oracle to_char().
SELECT TO_CHAR('now'::datetime, 'HH:MI:SS YYYY');
-------------
11:57:11 1999
FROM_CHAR(text, text)
---------------------
(returns DateTime)
FROM_CHAR - the PostgreSQL extension routine which read non-datetime
string and convert it to DateTime. This func. is inspire with the
Oracle to_date() routine, but in Oracle this func. return date only
and not support all keywords (format pictures).
SELECT FROM_CHAR('11:57:11 1999', 'HH:MI:SS YYYY');
----------------------------
Fri 01 Jan 11:57:11 1999 CET
TO_DATE(text, text)
-------------------
(returns Date)
TO_DATE - the Date function which read non-datetime (non-date) string
and convert it to date. All for thos func. is just as from_char().
This func. is inspire with the Oracle to_date() routine.
SELECT TO_DATE('11:57:11 1999', 'HH:MI:SS YYYY');
----------
01-01-1999
----------------------------------
String format-KeyWords and options:
----------------------------------
* TO_CHAR (..., 'format picture')
* FROM_CHAR (..., 'format picture')
* TO_DATE (..., 'format picture')
(Note: In Oracle manual is format-keyword called 'format pictures'.)
All keywords has suffixes (prefix or postfix), example for 2 hours:
keyword: HH (hour) 'HH' --> '02'
prefix: FM (fill mode) 'FMHH' --> '2'
postfix: TH (ordinal number) 'HHth' --> '02nd'
'FMHHth' --> '2nd'
Suffixes:
--------
FM - fill mode
02 --> FMHH --> 2
January , --> FMMonth --> January,
TH - upper ordinal number
02 --> HHTH --> 02ND
th - lower ordinal number
02 --> HHth --> 02th
KeyWords (format pictures):
--------------------------
HH - hour of day (01-12)
HH12 - -- // --
HH24 - hour (00-24)
MI - minute (00-59)
SS - socond (00-59)
SSSS - seconds past midnight (0-86399)
Y,YYY - year with comma (full PgSQL datetime range) digits)
YYYY - year (4 and more (full PgSQL datetime range) digits)
YYY - last 3 digits of year
YY - last 2 digits of year
Y - last digit of year
MONTH - full month name (upper) (9-letters)
Month - full month name - first character is upper (9-letters)
month - full month name - all characters is upper (9-letters)
MON - abbreviated month name (3-letters)
Mon - abbreviated month name (3-letters) - first character is upper
mon - abbreviated month name (3-letters) - all characters is upper
MM - month (01-12)
DAY - full day name (upper) (9-letters)
Day - full day name - first character is upper (9-letters)
day - full day name - all characters is upper (9-letters)
DY - abbreviated day name (3-letters) (upper)
Dy - abbreviated day name (3-letters) - first character is upper
Dy - abbreviated day name (3-letters) - all character is upper
DDD - day of year (001-366)
DD - day of month (01-31)
D - day of week (1-7; SUN=1)
WW - week number of year
CC - century (2-digits)
Q - quarter
RM - roman numeral month (I=JAN; I-XII)
W - week of month
J - julian day (days since January 1, 4712 BC)
AC / BC:
-------
TO-FROM CHAR routines support BC and AC postfix for years.
You can combine BC and AC with TH.
OTHER:
-----
'\' - must be use as double \\
'\\HH\\MI\\SS' --> 11\45\56
'"' - string berween a quotation marks is skipen and not
is parsed. If you wand write '"' to output you must
use \\"
'"Month: "Month' --> Month: November
'\\"YYYY Month\\"' --> "1999 November "
text - the PostgreSQL TO-FROM CHAR support text without '"',
but " text " is fastly and you have guarantee,
that this text not will interprete as keyword.
WARNING:
-------
You DON'T OMIT differention between fill mode (FM prefix)
and standard input in FROM_CHAR (TO_DATE), because this
routines can't scan your input string and conver it to
Datetime. See:
WRONG: FROM_CHAR('August 1999', 'Month YYYY');
RIGHT: FROM_CHAR('August 1999', 'Month YYYY');
or FROM_CHAR('August 1999', 'FMMonth YYYY');
(! Month is 9-letters string if you not set fill-mode !)
---------------------------
TODO / Now is not supported:
---------------------------
- spelled-out SP suffix ( 22 --> Twenty-two )
- AM/PM
- not supported number to character converting
TO_CHAR(number, 'format')
-------------------------------------------------------------------------------
- secondary products :-) ------------------------------------------------------
-------------------------------------------------------------------------------
ORDINAL(int4, text)
-------------------
* Translate number to ordinal number and return this as text
* Examples:
template1=> select ordinal(21212, 'TH');
ordinal
-------
21212ND
template1=> select ordinal(21212, 'th');
ordinal
-------
21212nd

View File

@ -0,0 +1,18 @@
#ifndef TO_FROM_CHAR_H
#define TO_FROM_CHAR_H
/*------
* For postgres
*------
*/
extern text *to_char(DateTime *dt, text *format);
extern DateTime *from_char(text *date_str, text *format);
extern DateADT to_date(text *date_str, text *format);
extern text *ordinal(int4 num, text *type);
extern char *months_full[]; /* full months name */
extern char *rm_months[]; /* roman numeral of months */
#endif

View File

@ -0,0 +1,29 @@
-- to-from_char.sql datetime routines --
--
-- Copyright (c) 1999, Karel Zak "Zakkr" <zakkr@zf.jcu.cz>
--
-- This file is distributed under the GNU General Public License
-- either version 2, or (at your option) any later version.
-- Define the new functions
--
create function to_char(datetime, text) returns text
as 'MODULE_PATHNAME'
language 'c';
create function from_char(text, text) returns datetime
as 'MODULE_PATHNAME'
language 'c';
create function to_date(text, text) returns date
as 'MODULE_PATHNAME'
language 'c';
create function ordinal(int, text) returns text
as 'MODULE_PATHNAME'
language 'c';
-- end of file