VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/time/RTTimeFormatDurationEx.cpp

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.1 KB
Line 
1/* $Id: RTTimeFormatDurationEx.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - RTTimeFormatInterval.
4 */
5
6/*
7 * Copyright (C) 2022-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include "internal/iprt.h"
42#include <iprt/time.h>
43
44#include <iprt/assert.h>
45#include <iprt/errcore.h>
46#include <iprt/string.h>
47
48
49static size_t rtTimeFormatDurationNumberEx(char *psz, uint32_t uValue, size_t cchValue)
50{
51 switch (cchValue)
52 {
53 case 10:
54 *psz++ = (uint8_t)(uValue / 1000000000) + '0';
55 uValue %= 1000000000;
56 RT_FALL_THROUGH();
57 case 9:
58 *psz++ = (uint8_t)(uValue / 100000000) + '0';
59 uValue %= 100000000;
60 RT_FALL_THROUGH();
61 case 8:
62 *psz++ = (uint8_t)(uValue / 10000000) + '0';
63 uValue %= 10000000;
64 RT_FALL_THROUGH();
65 case 7:
66 *psz++ = (uint8_t)(uValue / 1000000) + '0';
67 uValue %= 1000000;
68 RT_FALL_THROUGH();
69 case 6:
70 *psz++ = (uint8_t)(uValue / 100000) + '0';
71 uValue %= 100000;
72 RT_FALL_THROUGH();
73 case 5:
74 *psz++ = (uint8_t)(uValue / 10000) + '0';
75 uValue %= 10000;
76 RT_FALL_THROUGH();
77 case 4:
78 *psz++ = (uint8_t)(uValue / 1000) + '0';
79 uValue %= 1000;
80 RT_FALL_THROUGH();
81 case 3:
82 *psz++ = (uint8_t)(uValue / 100) + '0';
83 uValue %= 100;
84 RT_FALL_THROUGH();
85 case 2:
86 *psz++ = (uint8_t)(uValue / 10) + '0';
87 uValue %= 10;
88 RT_FALL_THROUGH();
89 case 1:
90 *psz++ = (uint8_t)uValue + '0';
91 break;
92 }
93 return cchValue;
94}
95
96
97static size_t rtTimeFormatDurationNumber(char *psz, uint32_t uValue)
98{
99 size_t cchValue;
100 if (uValue < 10)
101 cchValue = 1;
102 else if (uValue < 100)
103 cchValue = 2;
104 else if (uValue < 1000)
105 cchValue = 3;
106 else if (uValue < 10000)
107 cchValue = 4;
108 else if (uValue < 100000)
109 cchValue = 5;
110 else if (uValue < 1000000)
111 cchValue = 6;
112 else if (uValue < 10000000)
113 cchValue = 7;
114 else if (uValue < 100000000)
115 cchValue = 8;
116 else if (uValue < 1000000000)
117 cchValue = 9;
118 else
119 cchValue = 10;
120 return rtTimeFormatDurationNumberEx(psz, uValue, cchValue);
121}
122
123
124static ssize_t rtTimeFormatDurationCopyOutResult(char *pszDst, size_t cbDst, const char *pszValue, size_t cchValue)
125{
126 if (cbDst > cchValue)
127 {
128 memcpy(pszDst, pszValue, cchValue);
129 pszDst[cchValue] = '\0';
130 return cchValue;
131 }
132 if (cbDst)
133 {
134 memcpy(pszDst, pszValue, cbDst);
135 pszDst[cbDst - 1] = '\0';
136 }
137 return VERR_BUFFER_OVERFLOW;
138}
139
140
141/**
142 * Formats duration as best we can according to ISO-8601.
143 *
144 * The returned value is on the form "[-]PnnnnnWnDTnnHnnMnn.fffffffffS", where a
145 * sequence of 'n' can be between 1 and the given lenght, and all but the
146 * "nn.fffffffffS" part is optional and will only be outputted when the duration
147 * is sufficiently large. The code currently does not omit any inbetween
148 * elements other than the day count (D), so an exactly 7 day duration is
149 * formatted as "P1WT0H0M0.000000000S" when @a cFractionDigits is 9.
150 *
151 * @returns Number of characters in the output on success. VERR_BUFFER_OVEFLOW
152 * on failure.
153 * @retval VERR_OUT_OF_RANGE if @a cFractionDigits is too large.
154 * @param pszDst Pointer to the output buffer. In case of overflow,
155 * the max number of characters will be written and
156 * zero terminated, provided @a cbDst isn't zero.
157 * @param cbDst The size of the output buffer.
158 * @param pDuration The duration to format.
159 * @param cFractionDigits Number of digits in the second fraction part. Zero
160 * for whole no fraction. Max is 9 (nano seconds).
161 */
162RTDECL(ssize_t) RTTimeFormatDurationEx(char *pszDst, size_t cbDst, PCRTTIMESPEC pDuration, uint32_t cFractionDigits)
163{
164 AssertReturn(cFractionDigits <= 9, VERR_OUT_OF_RANGE);
165 AssertReturn(cbDst != 0, VERR_BUFFER_OVERFLOW);
166
167 /*
168 * Get the seconds and .
169 */
170 int64_t cNanoSecsSigned = RTTimeSpecGetNano(pDuration);
171
172 /* Special case: zero interval */
173 if (cNanoSecsSigned == 0)
174 return rtTimeFormatDurationCopyOutResult(pszDst, cbDst, RT_STR_TUPLE("PT0S"));
175
176 char szTmp[64];
177 size_t offTmp = 0;
178
179 /* Negative intervals aren't really allowed by the standard, but we slap a
180 minus in from of the 'P' and get on with it. */
181 if (cNanoSecsSigned < 0)
182 {
183 szTmp[offTmp++] = '-';
184 cNanoSecsSigned = -cNanoSecsSigned;
185 }
186 uint64_t cNanoSecs = (uint64_t)cNanoSecsSigned;
187
188 /* Emit the duration indicator: */
189 szTmp[offTmp++] = 'P';
190 size_t const offPostP = offTmp;
191
192 /* Any full weeks? */
193 if (cNanoSecs >= RT_NS_1WEEK)
194 {
195 uint64_t const cWeeks = cNanoSecs / RT_NS_1WEEK; /* (the max value here is 15250) */
196 cNanoSecs %= RT_NS_1WEEK;
197 offTmp += rtTimeFormatDurationNumber(&szTmp[offTmp], (uint32_t)cWeeks);
198 szTmp[offTmp++] = 'W';
199 }
200
201 /* Any full days?*/
202 if (cNanoSecs >= RT_NS_1DAY)
203 {
204 uint8_t const cDays = (uint8_t)(cNanoSecs / RT_NS_1DAY);
205 cNanoSecs %= RT_NS_1DAY;
206 szTmp[offTmp++] = '0' + cDays;
207 szTmp[offTmp++] = 'D';
208 }
209
210 szTmp[offTmp++] = 'T';
211
212 /* Hours: */
213 if (cNanoSecs >= RT_NS_1HOUR || offTmp > offPostP + 1)
214 {
215 uint8_t const cHours = (uint8_t)(cNanoSecs / RT_NS_1HOUR);
216 cNanoSecs %= RT_NS_1HOUR;
217 offTmp += rtTimeFormatDurationNumber(&szTmp[offTmp], cHours);
218 szTmp[offTmp++] = 'H';
219 }
220
221 /* Minutes: */
222 if (cNanoSecs >= RT_NS_1MIN || offTmp > offPostP + 1)
223 {
224 uint8_t const cMins = (uint8_t)(cNanoSecs / RT_NS_1MIN);
225 cNanoSecs %= RT_NS_1MIN;
226 offTmp += rtTimeFormatDurationNumber(&szTmp[offTmp], cMins);
227 szTmp[offTmp++] = 'M';
228 }
229
230 /* Seconds: */
231 uint8_t const cSecs = (uint8_t)(cNanoSecs / RT_NS_1SEC);
232 cNanoSecs %= RT_NS_1SEC;
233 offTmp += rtTimeFormatDurationNumber(&szTmp[offTmp], cSecs);
234 if (cFractionDigits > 0)
235 {
236 szTmp[offTmp++] = '.';
237 static uint32_t const s_auFactors[9] = { 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1 };
238 offTmp += rtTimeFormatDurationNumberEx(&szTmp[offTmp], (uint32_t)(cNanoSecs / s_auFactors[cFractionDigits - 1]),
239 cFractionDigits);
240 }
241 szTmp[offTmp++] = 'S';
242 szTmp[offTmp] = '\0';
243
244 return rtTimeFormatDurationCopyOutResult(pszDst, cbDst, szTmp, offTmp);
245}
246RT_EXPORT_SYMBOL(RTTimeFormatDurationEx);
247
248
249/**
250 * Formats duration as best we can according to ISO-8601, with no fraction.
251 *
252 * See RTTimeFormatDurationEx for details.
253 *
254 * @returns Number of characters in the output on success. VERR_BUFFER_OVEFLOW
255 * on failure.
256 * @param pszDst Pointer to the output buffer. In case of overflow,
257 * the max number of characters will be written and
258 * zero terminated, provided @a cbDst isn't zero.
259 * @param cbDst The size of the output buffer.
260 * @param pDuration The duration to format.
261 */
262RTDECL(int) RTTimeFormatDuration(char *pszDst, size_t cbDst, PCRTTIMESPEC pDuration)
263{
264 return RTTimeFormatDurationEx(pszDst, cbDst, pDuration, 0);
265}
266RT_EXPORT_SYMBOL(RTTimeFormatDuration);
267
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use