time_util.c
Go to the documentation of this file.
1 
10 #include "time_util.h"
11 #include "string_util.h"
12 #include "mcl_core/mcl_assert.h"
13 #include "mcl_core/mcl_memory.h"
14 
15 // Feature test for gmtime_r.
16 #define GMTIME_R_EXISTS ((defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE>= 1) || defined(_XOPEN_SOURCE) || \
17  defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_POSIX_SOURCE))
18 
19 #define TIMESTAMP_FIELD_COUNT 7
20 #define TIMESTAMP_DATE_INDEX 2
21 
22 mcl_error_t mcl_time_util_convert_to_iso_8601_format(const time_t *time_value, char *iso8601_formatted_time)
23 {
24  mcl_error_t return_code = MCL_OK;
25 
26 #if defined(WIN32) || defined(WIN64) || GMTIME_R_EXISTS
27  struct tm time_structure;
28 #endif
29 
30 #if defined(WIN32) || defined(WIN64)
31  errno_t result;
32 #else
33  struct tm *temp;
34 #endif
35 
36  MCL_DEBUG_ENTRY("const time_t *time_value = <%p>, char **iso8601_formatted_time = <%p>", time_value, iso8601_formatted_time);
37 
38  // Populate time structure for the given time value.
39 #if defined(WIN32) || defined(WIN64)
40  result = gmtime_s(&time_structure, time_value);
41  MCL_ASSERT_CODE_MESSAGE(0 == result, MCL_FAIL, "gmtime_s() function returns error.");
42 
43 #elif GMTIME_R_EXISTS
44  temp = gmtime_r(time_value, &time_structure);
45  MCL_ASSERT_CODE_MESSAGE(MCL_NULL != temp, MCL_FAIL, "gmtime_r() function returns null.");
46 #else
47  temp = gmtime(time_value);
48  MCL_ASSERT_CODE_MESSAGE(MCL_NULL != temp, MCL_FAIL, "gmtime() function returns null.");
49 #endif
50 
51  // Set empty right away.
52  iso8601_formatted_time[0] = MCL_NULL_CHAR;
53 
54  // Finalize the buffer.
55  iso8601_formatted_time[MCL_TIMESTAMP_LENGTH - MCL_NULL_CHAR_SIZE] = MCL_NULL_CHAR;
56 
57  // Compose the string in ISO 8601 date and time format.
58 #if defined(WIN32) || defined(WIN64) || GMTIME_R_EXISTS
59  if (0 == strftime(iso8601_formatted_time, MCL_TIMESTAMP_LENGTH, "%Y-%m-%dT%H:%M:%S.000Z", &time_structure))
60  {
61  MCL_DEBUG("File creation time can not be converted to ISO-8601 date and time format.");
62  return_code = MCL_FAIL;
63  }
64 #else
65  if (0 == strftime(iso8601_formatted_time, MCL_TIMESTAMP_LENGTH, "%Y-%m-%dT%H:%M:%S.000Z", temp))
66  {
67  MCL_DEBUG("File creation time can not be converted to ISO-8601 date and time format.");
68  return_code = MCL_FAIL;
69  }
70 #endif
71 
72  MCL_DEBUG_LEAVE("retVal = <%d>", return_code);
73  return return_code;
74 }
75 
77 {
78  const char characters_to_check[TIMESTAMP_FIELD_COUNT] = { '-', '-', 'T', ':', ':', '.', 'Z' };
79  const uint16_t maximum_values[TIMESTAMP_FIELD_COUNT] = { 2999, 12, 31, 23, 59, 59, 999 };
80  const uint8_t character_indexes_to_check[TIMESTAMP_FIELD_COUNT] = { 4, 7, 10, 13, 16, 19, 23 };
81  const char *position = timestamp;
82  char *end_pointer = MCL_NULL;
83  mcl_bool_t ok;
84  uint8_t index;
85  const mcl_size_t expected_timestamp_length = MCL_TIMESTAMP_LENGTH - MCL_NULL_CHAR_SIZE;
86  mcl_size_t actual_timestamp_length = 0;
87 
88  MCL_DEBUG_ENTRY("const char *timestamp = <%p>", timestamp);
89 
90  // Check timestamp length.
91  actual_timestamp_length = string_util_strlen(timestamp);
92  ok = expected_timestamp_length == actual_timestamp_length;
93 
94  // Check timestamp format.
95  for (index = 0; (index < TIMESTAMP_FIELD_COUNT) && (MCL_TRUE == ok); ++index)
96  {
97  ok = (characters_to_check[index] == timestamp[character_indexes_to_check[index]]);
98  }
99 
100  // Check date and time values.
101  for (index = 0; (index < TIMESTAMP_FIELD_COUNT) && (MCL_TRUE == ok); ++index)
102  {
103  // 10 is base.
104  mcl_int32_t int_value = (mcl_int32_t) string_util_strtol(position, 10, &end_pointer);
105 
106  ok = (maximum_values[index] >= int_value);
107 
108  if (MCL_TRUE == ok)
109  {
110  if (TIMESTAMP_DATE_INDEX >= index)
111  {
112  // Date values can not be zero.
113  ok = (int_value > 0);
114  }
115  else
116  {
117  ok = (int_value >= 0);
118  }
119  }
120 
121  // To show the address after the special character.
122  position = end_pointer + 1;
123  }
124 
125  MCL_DEBUG_LEAVE("retVal = <%d>", ok);
126  return ok;
127 }
128 
129 void time_util_get_time(mcl_time_t *current_time)
130 {
131  MCL_DEBUG_ENTRY("mcl_time_t *current_time = <%p>", current_time);
132 
133  time(current_time);
134 
135  MCL_DEBUG_LEAVE("retVal = void");
136 }
#define MCL_TIMESTAMP_LENGTH
Definition: mcl_time_util.h:23
size_t mcl_size_t
int32_t mcl_int32_t
long string_util_strtol(const char *source, int base, char **end_pointer)
Definition: string_util.c:402
Assert module header file.
Success.
#define MCL_DEBUG(...)
Definition: mcl_log_util.h:114
#define TIMESTAMP_DATE_INDEX
Definition: time_util.c:20
mcl_int32_t mcl_error_t
#define MCL_DEBUG_ENTRY(...)
Definition: mcl_log_util.h:115
String utility module header file.
mcl_error_t mcl_time_util_convert_to_iso_8601_format(const time_t *time_value, char *iso8601_formatted_time)
Definition: time_util.c:22
Time utility module interface header file.
#define MCL_ASSERT_CODE_MESSAGE(condition, return_code,...)
Definition: mcl_assert.h:77
#define MCL_NULL
#define TIMESTAMP_FIELD_COUNT
Definition: time_util.c:19
time_t mcl_time_t
mcl_uint8_t mcl_bool_t
void time_util_get_time(mcl_time_t *current_time)
Definition: time_util.c:129
#define MCL_NULL_CHAR_SIZE
mcl_bool_t mcl_time_util_validate_timestamp(const char *timestamp)
Definition: time_util.c:76
#define MCL_DEBUG_LEAVE(...)
Definition: mcl_log_util.h:116
#define MCL_TRUE
Internal failure in MCL.
mcl_size_t string_util_strlen(const char *buffer)
Definition: string_util.c:35
#define MCL_NULL_CHAR
Time utility module header file.
Memory module interface header file.