Skip to content

Commit 4869ef5

Browse files
qinshiyurasifr
authored andcommitted
compatible function new_time
1 parent 5002a0d commit 4869ef5

5 files changed

Lines changed: 306 additions & 2 deletions

File tree

contrib/orafce/builtins.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ extern PGDLLEXPORT Datum ora_systimestamp(PG_FUNCTION_ARGS);
307307
extern PGDLLEXPORT Datum ora_sys_extract_utc(PG_FUNCTION_ARGS);
308308
extern PGDLLEXPORT Datum ora_days_between(PG_FUNCTION_ARGS);
309309
extern PGDLLEXPORT Datum ora_days_between_tmtz(PG_FUNCTION_ARGS);
310+
extern PGDLLEXPORT Datum new_time(PG_FUNCTION_ARGS);
310311

311312

312313

contrib/orafce/datefuncs.c

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,15 @@
2929
#include <funcapi.h>
3030

3131

32+
#define NUMBER_OF_TIME_ZONES 18
33+
34+
3235
PG_FUNCTION_INFO_V1(ora_fromtz);
3336
PG_FUNCTION_INFO_V1(ora_systimestamp);
3437
PG_FUNCTION_INFO_V1(ora_sys_extract_utc);
3538
PG_FUNCTION_INFO_V1(ora_days_between);
3639
PG_FUNCTION_INFO_V1(ora_days_between_tmtz);
40+
PG_FUNCTION_INFO_V1(new_time);
3741

3842

3943

@@ -353,3 +357,152 @@ Datum ora_days_between_tmtz(PG_FUNCTION_ARGS)
353357

354358
}
355359

360+
361+
/********************************************************************
362+
*
363+
* FUnction:oratimestamptz2timestamp
364+
*
365+
* Description:recover timestamp with zone to timestamp without zone
366+
*
367+
* Return:timestamp with out zone
368+
*
369+
* Note:oracle compatible timestamp transfer
370+
*
371+
********************************************************************/
372+
static Timestamp
373+
oratimestamptz2timestamp(TimestampTz timestamp)
374+
{
375+
Timestamp result;
376+
struct pg_tm tt,
377+
*tm = &tt;
378+
fsec_t fsec;
379+
int tz;
380+
381+
if (TIMESTAMP_NOT_FINITE(timestamp))
382+
result = timestamp;
383+
else
384+
{
385+
if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
386+
ereport(ERROR,
387+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
388+
errmsg("timestamp out of range")));
389+
if (tm2timestamp(tm, fsec, NULL, &result) != 0)
390+
ereport(ERROR,
391+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
392+
errmsg("timestamp out of range")));
393+
}
394+
return result;
395+
}
396+
397+
398+
/********************************************************************
399+
*
400+
* FUnction:new_time
401+
*
402+
* Description:convert the time in the specified time zone to another time zone
403+
*
404+
* Return:a new timestamp
405+
*
406+
* Note:there is olney support timestamp without time zone
407+
*
408+
********************************************************************/
409+
Datum
410+
new_time(PG_FUNCTION_ARGS)
411+
{
412+
TimestampTz timestamptz = PG_GETARG_TIMESTAMP(0);
413+
text *arg1 = PG_GETARG_TEXT_P(1);
414+
text *arg2 = PG_GETARG_TEXT_P(2);
415+
int tz, i, zone1 = 0, zone2 = 0, tmp1 = 0, tmp2 = 0, day;
416+
struct pg_tm tt, *tm = &tt;
417+
fsec_t fsec;
418+
const char *tzn = NULL;
419+
char *pre_zone = NULL, *post_zone = NULL ;
420+
char *zone[NUMBER_OF_TIME_ZONES] = {"ast", "adt", "bst", "bdt", "cst", "cdt", "est", "edt", "gmt", "hst", "hdt", "mst", "mdt", "nst", "pst", "pdt", "yst", "ydt"};
421+
int zone_num[NUMBER_OF_TIME_ZONES] = { -4, -3, -11, -10, -6, -5, -5, -4, 0, -10, -9, -7, -6, -3, -8, -7, -9, -8};
422+
Timestamp result;
423+
424+
Timestamp timestamp;
425+
426+
timestamp = oratimestamptz2timestamp(timestamptz);
427+
428+
/*ignore input parameter case*/
429+
pre_zone = str_tolower(VARDATA_ANY(arg1), VARSIZE_ANY_EXHDR(arg1), PG_GET_COLLATION());
430+
post_zone = str_tolower(VARDATA_ANY(arg2), VARSIZE_ANY_EXHDR(arg2), PG_GET_COLLATION());
431+
432+
//timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, pg_tzset("GMT"));
433+
timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL);
434+
435+
for (i = 0; i < NUMBER_OF_TIME_ZONES; i++)
436+
{
437+
if (!strcmp(zone[i], pre_zone))
438+
{
439+
zone1 = zone_num[i];
440+
tmp1 = 1;
441+
}
442+
443+
if (!strcmp(zone[i], post_zone))
444+
{
445+
zone2 = zone_num[i];
446+
tmp2 = 1;
447+
}
448+
}
449+
450+
if ((tmp1 == 0) || (tmp2 == 0))
451+
ereport(ERROR,
452+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
453+
errmsg("illegal timezone!")));
454+
455+
/*transfer date into Julian day*/
456+
day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
457+
tm->tm_hour = tm->tm_hour + zone2 - zone1;
458+
459+
/* if the zone is nst, there need to deal minutes, becaus nst is 3.5, is not 3 */
460+
if (0 == strcmp("nst", post_zone))
461+
{
462+
if (tm->tm_min > 29)
463+
{
464+
tm->tm_min = tm->tm_min - 30;
465+
}
466+
else
467+
{
468+
tm->tm_min = tm->tm_min + 30;
469+
tm->tm_hour = tm->tm_hour - 1;
470+
}
471+
}
472+
473+
if(0 == strcmp("nst",pre_zone))
474+
{
475+
if (tm->tm_min < 29)
476+
{
477+
tm->tm_min = tm->tm_min + 30;
478+
}
479+
else
480+
{
481+
tm->tm_min = tm->tm_min - 30;
482+
tm->tm_hour = tm->tm_hour + 1;
483+
}
484+
}
485+
486+
/*if hour bigger than 24, or small than 0, need to change the day*/
487+
if (tm->tm_hour >= 24)
488+
{
489+
tm->tm_hour -= 24;
490+
day += 1;
491+
}
492+
else if (tm->tm_hour < 0)
493+
{
494+
tm->tm_hour += 24;
495+
day -= 1;
496+
}
497+
498+
/*transfer Julian day into date format*/
499+
j2date(day, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
500+
fsec = 0;
501+
if (tm2timestamp(tm, fsec, &tz, &result) != 0)
502+
ereport(ERROR,
503+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
504+
errmsg("timestamp out of range")));
505+
506+
PG_RETURN_TIMESTAMP(result);
507+
}
508+

contrib/orafce/expected/datefuncs.out

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,3 +282,124 @@ select oracle.subtract('2019-11-25 16:51:20'::timestamp,NULL) from dual;
282282

283283
select oracle.subtract(NULL,NULL) from dual;
284284
ERROR: function oracle.subtract(unknown, unknown) is not unique at character 8
285+
--new_time function
286+
select oracle.new_time(timestamp '2020-12-12 17:45:18', 'AST', 'ADT') from dual;
287+
new_time
288+
---------------------
289+
2020-12-12 18:45:18
290+
(1 row)
291+
292+
select oracle.new_time(timestamp '2020-12-12 17:45:18', 'BST', 'BDT') from dual;
293+
new_time
294+
---------------------
295+
2020-12-12 18:45:18
296+
(1 row)
297+
298+
select oracle.new_time(timestamp '2020-12-12 17:45:18', 'CST', 'CDT') from dual;
299+
new_time
300+
---------------------
301+
2020-12-12 18:45:18
302+
(1 row)
303+
304+
select oracle.new_time(timestamp '2020-12-12 17:45:18', 'EST', 'EDT') from dual;
305+
new_time
306+
---------------------
307+
2020-12-12 18:45:18
308+
(1 row)
309+
310+
select oracle.new_time(timestamp '2020-12-12 17:45:18', 'HST', 'HDT') from dual;
311+
new_time
312+
---------------------
313+
2020-12-12 18:45:18
314+
(1 row)
315+
316+
select oracle.new_time(timestamp '2020-12-12 17:45:18', 'MST', 'MDT') from dual;
317+
new_time
318+
---------------------
319+
2020-12-12 18:45:18
320+
(1 row)
321+
322+
select oracle.new_time(timestamp '2020-12-12 17:45:18', 'PST', 'PDT') from dual;
323+
new_time
324+
---------------------
325+
2020-12-12 18:45:18
326+
(1 row)
327+
328+
select oracle.new_time(timestamp '2020-12-12 17:45:18', 'YST', 'YDT') from dual;
329+
new_time
330+
---------------------
331+
2020-12-12 18:45:18
332+
(1 row)
333+
334+
select oracle.new_time(timestamp '2020-12-12 17:45:18', 'GMT', 'EDT') from dual;
335+
new_time
336+
---------------------
337+
2020-12-12 13:45:18
338+
(1 row)
339+
340+
select oracle.new_time(timestamp '2020-12-12 17:45:18', 'NST', 'GMT') from dual;
341+
new_time
342+
---------------------
343+
2020-12-12 21:15:18
344+
(1 row)
345+
346+
select oracle.new_time('2020-10-12 17:42:58 +08'::timestamptz, 'AST', 'ADT') from dual;
347+
new_time
348+
---------------------
349+
2020-10-12 18:42:58
350+
(1 row)
351+
352+
select oracle.new_time('2020-11-12 17:42:58 +08'::timestamptz, 'BST', 'BDT') from dual;
353+
new_time
354+
---------------------
355+
2020-11-12 18:42:58
356+
(1 row)
357+
358+
select oracle.new_time('2020-12-12 13:45:58 +08'::timestamptz, 'CST', 'CDT') from dual;
359+
new_time
360+
---------------------
361+
2020-12-12 14:45:58
362+
(1 row)
363+
364+
select oracle.new_time('2020-10-12 13:45:18 +08'::timestamptz, 'EST', 'EDT') from dual;
365+
new_time
366+
---------------------
367+
2020-10-12 14:45:18
368+
(1 row)
369+
370+
select oracle.new_time('2020-11-12 17:49:18 +08'::timestamptz, 'HST', 'HDT') from dual;
371+
new_time
372+
---------------------
373+
2020-11-12 18:49:18
374+
(1 row)
375+
376+
select oracle.new_time('2020-12-12 17:49:28 +08'::timestamptz, 'MST', 'MDT') from dual;
377+
new_time
378+
---------------------
379+
2020-12-12 18:49:28
380+
(1 row)
381+
382+
select oracle.new_time('2020-10-12 17:45:28 +08'::timestamptz, 'PST', 'PDT') from dual;
383+
new_time
384+
---------------------
385+
2020-10-12 18:45:28
386+
(1 row)
387+
388+
select oracle.new_time('2020-10-12 16:45:18 +08'::timestamptz, 'YST', 'YDT') from dual;
389+
new_time
390+
---------------------
391+
2020-10-12 17:45:18
392+
(1 row)
393+
394+
select oracle.new_time('2020-11-12 16:41:28 +08'::timestamptz, 'GMT', 'EDT') from dual;
395+
new_time
396+
---------------------
397+
2020-11-12 12:41:28
398+
(1 row)
399+
400+
select oracle.new_time('2020-12-12 17:41:18 +08'::timestamptz, 'NST', 'GMT') from dual;
401+
new_time
402+
---------------------
403+
2020-12-12 21:11:18
404+
(1 row)
405+

contrib/orafce/orafce--3.17.sql

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6260,4 +6260,11 @@ $$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
62606260
CREATE OR REPLACE FUNCTION oracle.subtract(timestamptz, timestamptz)
62616261
RETURNS double precision AS $$
62626262
SELECT date_part('epoch', ($1 OPERATOR(pg_catalog.-) $2)/3600/24);
6263-
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
6263+
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
6264+
6265+
--new_time function
6266+
CREATE FUNCTION oracle.new_time(timestamptz, text, text)
6267+
RETURNS timestamp
6268+
AS 'MODULE_PATHNAME','new_time'
6269+
LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
6270+
COMMENT ON FUNCTION oracle.new_time(timestamptz, text, text) IS 'returns the date and time in time zone timezone2 when date and time in time zone timezone1 are date.';

contrib/orafce/sql/datefuncs.sql

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,26 @@ select oracle.subtract('2019-11-25 16:51:20'::timestamp,'3267.123'::numeric) fro
7070
select oracle.subtract('2019-11-25 16:51:20'::timestamp, '2018-11-25 16:51:12'::timestamp) from dual;
7171
select oracle.subtract(NULL,'3267.123'::numeric) from dual;
7272
select oracle.subtract('2019-11-25 16:51:20'::timestamp,NULL) from dual;
73-
select oracle.subtract(NULL,NULL) from dual;
73+
select oracle.subtract(NULL,NULL) from dual;
74+
75+
--new_time function
76+
select oracle.new_time(timestamp '2020-12-12 17:45:18', 'AST', 'ADT') from dual;
77+
select oracle.new_time(timestamp '2020-12-12 17:45:18', 'BST', 'BDT') from dual;
78+
select oracle.new_time(timestamp '2020-12-12 17:45:18', 'CST', 'CDT') from dual;
79+
select oracle.new_time(timestamp '2020-12-12 17:45:18', 'EST', 'EDT') from dual;
80+
select oracle.new_time(timestamp '2020-12-12 17:45:18', 'HST', 'HDT') from dual;
81+
select oracle.new_time(timestamp '2020-12-12 17:45:18', 'MST', 'MDT') from dual;
82+
select oracle.new_time(timestamp '2020-12-12 17:45:18', 'PST', 'PDT') from dual;
83+
select oracle.new_time(timestamp '2020-12-12 17:45:18', 'YST', 'YDT') from dual;
84+
select oracle.new_time(timestamp '2020-12-12 17:45:18', 'GMT', 'EDT') from dual;
85+
select oracle.new_time(timestamp '2020-12-12 17:45:18', 'NST', 'GMT') from dual;
86+
select oracle.new_time('2020-10-12 17:42:58 +08'::timestamptz, 'AST', 'ADT') from dual;
87+
select oracle.new_time('2020-11-12 17:42:58 +08'::timestamptz, 'BST', 'BDT') from dual;
88+
select oracle.new_time('2020-12-12 13:45:58 +08'::timestamptz, 'CST', 'CDT') from dual;
89+
select oracle.new_time('2020-10-12 13:45:18 +08'::timestamptz, 'EST', 'EDT') from dual;
90+
select oracle.new_time('2020-11-12 17:49:18 +08'::timestamptz, 'HST', 'HDT') from dual;
91+
select oracle.new_time('2020-12-12 17:49:28 +08'::timestamptz, 'MST', 'MDT') from dual;
92+
select oracle.new_time('2020-10-12 17:45:28 +08'::timestamptz, 'PST', 'PDT') from dual;
93+
select oracle.new_time('2020-10-12 16:45:18 +08'::timestamptz, 'YST', 'YDT') from dual;
94+
select oracle.new_time('2020-11-12 16:41:28 +08'::timestamptz, 'GMT', 'EDT') from dual;
95+
select oracle.new_time('2020-12-12 17:41:18 +08'::timestamptz, 'NST', 'GMT') from dual;

0 commit comments

Comments
 (0)