f30fa07507750a2f93adc68894b633d423072c66
[gnulib.git] / lib / dtotimespec.c
1 /* Convert double to timespec.
2
3    Copyright (C) 2011-2012 Free Software Foundation, Inc.
4
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18 /* written by Paul Eggert */
19
20 /* Convert the double value SEC to a struct timespec.  Round toward
21    positive infinity.  On overflow, return an extremal value.  */
22
23 #include <config.h>
24
25 #include "timespec.h"
26
27 #include "intprops.h"
28
29 struct timespec
30 dtotimespec (double sec)
31 {
32   enum { BILLION = 1000 * 1000 * 1000 };
33   double min_representable = TYPE_MINIMUM (time_t);
34   double max_representable =
35     ((TYPE_MAXIMUM (time_t) * (double) BILLION + (BILLION - 1))
36      / BILLION);
37   struct timespec r;
38
39   if (! (min_representable < sec))
40     {
41       r.tv_sec = TYPE_MINIMUM (time_t);
42       r.tv_nsec = 0;
43     }
44   else if (! (sec < max_representable))
45     {
46       r.tv_sec = TYPE_MAXIMUM (time_t);
47       r.tv_nsec = BILLION - 1;
48     }
49   else
50     {
51       time_t s = sec;
52       double frac = BILLION * (sec - s);
53       long ns = frac;
54       ns += ns < frac;
55       s += ns / BILLION;
56       ns %= BILLION;
57
58       if (ns < 0)
59         {
60           s--;
61           ns += BILLION;
62         }
63
64       r.tv_sec = s;
65       r.tv_nsec = ns;
66     }
67
68   return r;
69 }