|
26 | 26 | #include "funcapi.h"
|
27 | 27 | #include "miscadmin.h"
|
28 | 28 | #include "nodes/nodeFuncs.h"
|
| 29 | +#include "parser/scansup.h" |
29 | 30 | #include "utils/builtins.h"
|
30 | 31 | #include "utils/date.h"
|
31 | 32 | #include "utils/datetime.h"
|
@@ -3162,6 +3163,90 @@ DecodeSpecial(int field, const char *lowtoken, int *val)
|
3162 | 3163 | }
|
3163 | 3164 |
|
3164 | 3165 |
|
| 3166 | +/* DecodeTimezoneName() |
| 3167 | + * Interpret string as a timezone abbreviation or name. |
| 3168 | + * Throw error if the name is not recognized. |
| 3169 | + * |
| 3170 | + * The return value indicates what kind of zone identifier it is: |
| 3171 | + * TZNAME_FIXED_OFFSET: fixed offset from UTC |
| 3172 | + * TZNAME_DYNTZ: dynamic timezone abbreviation |
| 3173 | + * TZNAME_ZONE: full tzdb zone name |
| 3174 | + * |
| 3175 | + * For TZNAME_FIXED_OFFSET, *offset receives the UTC offset (in seconds, |
| 3176 | + * with ISO sign convention: positive is east of Greenwich). |
| 3177 | + * For the other two cases, *tz receives the timezone struct representing |
| 3178 | + * the zone name or the abbreviation's underlying zone. |
| 3179 | + */ |
| 3180 | +int |
| 3181 | +DecodeTimezoneName(const char *tzname, int *offset, pg_tz **tz) |
| 3182 | +{ |
| 3183 | + char *lowzone; |
| 3184 | + int dterr, |
| 3185 | + type; |
| 3186 | + DateTimeErrorExtra extra; |
| 3187 | + |
| 3188 | + /* |
| 3189 | + * First we look in the timezone abbreviation table (to handle cases like |
| 3190 | + * "EST"), and if that fails, we look in the timezone database (to handle |
| 3191 | + * cases like "America/New_York"). This matches the order in which |
| 3192 | + * timestamp input checks the cases; it's important because the timezone |
| 3193 | + * database unwisely uses a few zone names that are identical to offset |
| 3194 | + * abbreviations. |
| 3195 | + */ |
| 3196 | + |
| 3197 | + /* DecodeTimezoneAbbrev requires lowercase input */ |
| 3198 | + lowzone = downcase_truncate_identifier(tzname, |
| 3199 | + strlen(tzname), |
| 3200 | + false); |
| 3201 | + |
| 3202 | + dterr = DecodeTimezoneAbbrev(0, lowzone, &type, offset, tz, &extra); |
| 3203 | + if (dterr) |
| 3204 | + DateTimeParseError(dterr, &extra, NULL, NULL, NULL); |
| 3205 | + |
| 3206 | + if (type == TZ || type == DTZ) |
| 3207 | + { |
| 3208 | + /* fixed-offset abbreviation, return the offset */ |
| 3209 | + return TZNAME_FIXED_OFFSET; |
| 3210 | + } |
| 3211 | + else if (type == DYNTZ) |
| 3212 | + { |
| 3213 | + /* dynamic-offset abbreviation, return its referenced timezone */ |
| 3214 | + return TZNAME_DYNTZ; |
| 3215 | + } |
| 3216 | + else |
| 3217 | + { |
| 3218 | + /* try it as a full zone name */ |
| 3219 | + *tz = pg_tzset(tzname); |
| 3220 | + if (*tz == NULL) |
| 3221 | + ereport(ERROR, |
| 3222 | + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| 3223 | + errmsg("time zone \"%s\" not recognized", tzname))); |
| 3224 | + return TZNAME_ZONE; |
| 3225 | + } |
| 3226 | +} |
| 3227 | + |
| 3228 | +/* DecodeTimezoneNameToTz() |
| 3229 | + * Interpret string as a timezone abbreviation or name. |
| 3230 | + * Throw error if the name is not recognized. |
| 3231 | + * |
| 3232 | + * This is a simple wrapper for DecodeTimezoneName that produces a pg_tz * |
| 3233 | + * result in all cases. |
| 3234 | + */ |
| 3235 | +pg_tz * |
| 3236 | +DecodeTimezoneNameToTz(const char *tzname) |
| 3237 | +{ |
| 3238 | + pg_tz *result; |
| 3239 | + int offset; |
| 3240 | + |
| 3241 | + if (DecodeTimezoneName(tzname, &offset, &result) == TZNAME_FIXED_OFFSET) |
| 3242 | + { |
| 3243 | + /* fixed-offset abbreviation, get a pg_tz descriptor for that */ |
| 3244 | + result = pg_tzset_offset(-offset); /* flip to POSIX sign convention */ |
| 3245 | + } |
| 3246 | + return result; |
| 3247 | +} |
| 3248 | + |
| 3249 | + |
3165 | 3250 | /* ClearPgItmIn
|
3166 | 3251 | *
|
3167 | 3252 | * Zero out a pg_itm_in
|
|
0 commit comments