libs/c-timestamp/timestamp_format.c (120 lines of code) (raw):

/* * Copyright (c) 2014 Christian Hansen <chansen@cpan.org> * <https://github.com/chansen/c-timestamp> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <stddef.h> #include "timestamp.h" static const uint16_t DayOffset[13] = { 0, 306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275 }; /* Rata Die algorithm by Peter Baum */ static void rdn_to_ymd(uint32_t rdn, uint16_t *yp, uint16_t *mp, uint16_t *dp) { uint32_t Z, H, A, B; uint16_t y, m, d; Z = rdn + 306; H = 100 * Z - 25; A = H / 3652425; B = A - (A >> 2); y = (100 * B + H) / 36525; d = B + Z - (1461 * y >> 2); m = (535 * d + 48950) >> 14; if (m > 12) y++, m -= 12; *yp = y; *mp = m; *dp = d - DayOffset[m]; } #define EPOCH INT64_C(62135683200) /* 1970-01-01T00:00:00 */ static const uint32_t Pow10[10] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; static size_t timestamp_format_internal(char *dst, size_t len, const timestamp_t *tsp, const int precision) { unsigned char *p; uint64_t sec; uint32_t rdn, v; uint16_t y, m, d; size_t dlen; dlen = sizeof("YYYY-MM-DDThh:mm:ssZ") - 1; if (tsp->offset) dlen += 5; /* hh:mm */ if (precision) dlen += 1 + precision; if (dlen >= len) return 0; sec = tsp->sec + tsp->offset * 60 + EPOCH; rdn = sec / 86400; rdn_to_ymd(rdn, &y, &m, &d); /* * 1 * 0123456789012345678 * YYYY-MM-DDThh:mm:ss */ p = (unsigned char *)dst; v = sec % 86400; p[18] = '0' + (v % 10); v /= 10; p[17] = '0' + (v % 6); v /= 6; p[16] = ':'; p[15] = '0' + (v % 10); v /= 10; p[14] = '0' + (v % 6); v /= 6; p[13] = ':'; p[12] = '0' + (v % 10); v /= 10; p[11] = '0' + (v % 10); p[10] = 'T'; p[ 9] = '0' + (d % 10); d /= 10; p[ 8] = '0' + (d % 10); p[ 7] = '-'; p[ 6] = '0' + (m % 10); m /= 10; p[ 5] = '0' + (m % 10); p[ 4] = '-'; p[ 3] = '0' + (y % 10); y /= 10; p[ 2] = '0' + (y % 10); y /= 10; p[ 1] = '0' + (y % 10); y /= 10; p[ 0] = '0' + (y % 10); p += 19; if (precision) { v = tsp->nsec / Pow10[9 - precision]; switch (precision) { case 9: p[9] = '0' + (v % 10); v /= 10; case 8: p[8] = '0' + (v % 10); v /= 10; case 7: p[7] = '0' + (v % 10); v /= 10; case 6: p[6] = '0' + (v % 10); v /= 10; case 5: p[5] = '0' + (v % 10); v /= 10; case 4: p[4] = '0' + (v % 10); v /= 10; case 3: p[3] = '0' + (v % 10); v /= 10; case 2: p[2] = '0' + (v % 10); v /= 10; case 1: p[1] = '0' + (v % 10); } p[0] = '.'; p += 1 + precision; } if (!tsp->offset) *p++ = 'Z'; else { if (tsp->offset < 0) p[0] = '-', v = -tsp->offset; else p[0] = '+', v = tsp->offset; p[5] = '0' + (v % 10); v /= 10; p[4] = '0' + (v % 6); v /= 6; p[3] = ':'; p[2] = '0' + (v % 10); v /= 10; p[1] = '0' + (v % 10); p += 6; } *p = 0; return dlen; } /* * 1 2 3 * 12345678901234567890123456789012345 (+ null-terminator) * YYYY-MM-DDThh:mm:ssZ * YYYY-MM-DDThh:mm:ss±hh:mm * YYYY-MM-DDThh:mm:ss.123Z * YYYY-MM-DDThh:mm:ss.123±hh:mm * YYYY-MM-DDThh:mm:ss.123456Z * YYYY-MM-DDThh:mm:ss.123456±hh:mm * YYYY-MM-DDThh:mm:ss.123456789Z * YYYY-MM-DDThh:mm:ss.123456789±hh:mm */ size_t timestamp_format(char *dst, size_t len, const timestamp_t *tsp) { uint32_t f; int precision; if (!timestamp_valid(tsp)) return 0; f = tsp->nsec; if (!f) precision = 0; else { if ((f % 1000000) == 0) precision = 3; else if ((f % 1000) == 0) precision = 6; else precision = 9; } return timestamp_format_internal(dst, len, tsp, precision); } size_t timestamp_format_precision(char *dst, size_t len, const timestamp_t *tsp, int precision) { if (!timestamp_valid(tsp) || precision < 0 || precision > 9) return 0; return timestamp_format_internal(dst, len, tsp, precision); }