iso8601.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "../libnetdata.h"
  3. size_t iso8601_datetime_ut(char *buffer, size_t len, usec_t now_ut, ISO8601_OPTIONS options) {
  4. if(unlikely(!buffer || len == 0))
  5. return 0;
  6. time_t t = (time_t)(now_ut / USEC_PER_SEC);
  7. struct tm *tmp, tmbuf;
  8. if(options & ISO8601_UTC)
  9. // Use gmtime_r for UTC time conversion.
  10. tmp = gmtime_r(&t, &tmbuf);
  11. else
  12. // Use localtime_r for local time conversion.
  13. tmp = localtime_r(&t, &tmbuf);
  14. if (unlikely(!tmp)) {
  15. buffer[0] = '\0';
  16. return 0;
  17. }
  18. // Format the date and time according to the ISO 8601 format.
  19. size_t used_length = strftime(buffer, len, "%Y-%m-%dT%H:%M:%S", tmp);
  20. if (unlikely(used_length == 0)) {
  21. buffer[0] = '\0';
  22. return 0;
  23. }
  24. if(options & ISO8601_MILLISECONDS) {
  25. // Calculate the remaining microseconds
  26. int milliseconds = (int) ((now_ut % USEC_PER_SEC) / USEC_PER_MS);
  27. if(milliseconds && len - used_length > 4)
  28. used_length += snprintfz(buffer + used_length, len - used_length, ".%03d", milliseconds);
  29. }
  30. else if(options & ISO8601_MICROSECONDS) {
  31. // Calculate the remaining microseconds
  32. int microseconds = (int) (now_ut % USEC_PER_SEC);
  33. if(microseconds && len - used_length > 7)
  34. used_length += snprintfz(buffer + used_length, len - used_length, ".%06d", microseconds);
  35. }
  36. if(options & ISO8601_UTC) {
  37. if(used_length + 1 < len) {
  38. buffer[used_length++] = 'Z';
  39. buffer[used_length] = '\0'; // null-terminate the string.
  40. }
  41. }
  42. else {
  43. // Calculate the timezone offset in hours and minutes from UTC.
  44. long offset = tmbuf.tm_gmtoff;
  45. int hours = (int) (offset / 3600); // Convert offset seconds to hours.
  46. int minutes = (int) ((offset % 3600) / 60); // Convert remainder to minutes (keep the sign for minutes).
  47. // Check if timezone is UTC.
  48. if(hours == 0 && minutes == 0) {
  49. // For UTC, append 'Z' to the timestamp.
  50. if(used_length + 1 < len) {
  51. buffer[used_length++] = 'Z';
  52. buffer[used_length] = '\0'; // null-terminate the string.
  53. }
  54. }
  55. else {
  56. // For non-UTC, format the timezone offset. Omit minutes if they are zero.
  57. if(minutes == 0) {
  58. // Check enough space is available for the timezone offset string.
  59. if(used_length + 3 < len) // "+hh\0"
  60. used_length += snprintfz(buffer + used_length, len - used_length, "%+03d", hours);
  61. }
  62. else {
  63. // Check enough space is available for the timezone offset string.
  64. if(used_length + 6 < len) // "+hh:mm\0"
  65. used_length += snprintfz(buffer + used_length, len - used_length,
  66. "%+03d:%02d", hours, abs(minutes));
  67. }
  68. }
  69. }
  70. return used_length;
  71. }