Mantid
Loading...
Searching...
No Matches
DateAndTimeHelpers.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
9#include <Poco/DateTime.h>
10#include <Poco/DateTimeFormat.h>
11#include <Poco/DateTimeParser.h>
12#include <numeric>
13#include <stdexcept>
14
15namespace {
16std::tuple<bool, size_t, std::string> isARGUSDateTime(const std::string &date) {
17 // Some ARGUS files have an invalid date with a space instead of zero.
18 // To enable such files to be loaded we correct the date and issue a warning
19 // Normal ISO8601 Date "2009-07-08T10:23:50"
20 // Possible Argus Format "2009-07- 8T10:23:50"
21
22 // (ticket #4017).
23 // just take the date not the time or any date-time separator
24 std::string strippedDate = date.substr(0, 10);
25 const size_t nSpace = strippedDate.find(' ');
26 return std::make_tuple(nSpace != std::string::npos, nSpace, strippedDate);
27}
28} // namespace
29
31// Initialize the logger
32Logger g_log("DateAndTime");
33
39Types::Core::DateAndTime createFromSanitizedISO8601(const std::string &date) {
40 return Types::Core::DateAndTime(verifyAndSanitizeISO8601(date));
41}
42
51std::string verifyAndSanitizeISO8601(const std::string &date, bool displayWarnings) {
52 auto res = isARGUSDateTime(date);
53
54 if (std::get<0>(res)) {
55 auto time = date;
56 if (displayWarnings) {
57 g_log.warning() << "Invalid ISO8601 date " << date;
58 }
59
60 auto nSpace = std::get<1>(res);
61
62 time[nSpace] = '0'; // replace space with 0
63
64 // Do again in case of second space
65 auto strippedDate = std::get<2>(res);
66 strippedDate[nSpace] = '0';
67
68 const size_t nSecondSpace = strippedDate.find(' ');
69 if (nSecondSpace != std::string::npos)
70 time[nSecondSpace] = '0';
71 if (displayWarnings) {
72 g_log.warning() << " corrected to " << time << '\n';
73 }
74
75 return time;
76 }
77
78 return date;
79}
80
85Types::Core::DateAndTime averageSorted(const std::vector<Types::Core::DateAndTime> &times) {
86 if (times.empty())
87 throw std::invalid_argument("Cannot find average of empty vector");
88
89 // to avoid overflow subtract the first time off from everything
90 // and find the average in between
91 const int64_t first = times.begin()->totalNanoseconds();
92 int64_t total =
93 std::accumulate(times.begin(), times.end(), int64_t{0}, [first](int64_t a, const Types::Core::DateAndTime time) {
94 return a + (time.totalNanoseconds() - first);
95 });
96
97 double avg = static_cast<double>(total) / static_cast<double>(times.size());
98
99 return times.front() + static_cast<int64_t>(avg);
100}
101
102Types::Core::DateAndTime averageSorted(const std::vector<Types::Core::DateAndTime> &times,
103 const std::vector<double> &weights) {
104 if (times.empty())
105 throw std::invalid_argument("Cannot find average of empty vector");
106 if (times.size() != weights.size())
107 throw std::invalid_argument("time and weight vectors must be the same length");
108 if (times.size() == 1)
109 return times.front();
110
111 double totalWeight = std::accumulate(weights.begin(), weights.end(), 0.);
112
113 // to avoid overflow subtract the first time off from everything
114 // and find the average in between
115 const int64_t first = times.begin()->totalNanoseconds();
116
117 // second operation is done to each parallel vector element
118 // first operation accumulates the result
119 double totalValue = std::inner_product(times.begin(), times.end(), weights.begin(), double{0.}, std::plus<>(),
120 [first](const Types::Core::DateAndTime time, const double weight) {
121 return static_cast<double>(time.totalNanoseconds() - first) * weight;
122 });
123
124 // add the result to the original first value
125 return times.front() + static_cast<int64_t>(totalValue / totalWeight);
126}
127
128} // namespace Mantid::Kernel::DateAndTimeHelpers
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition: Logger.h:52
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
MANTID_KERNEL_DLL Types::Core::DateAndTime createFromSanitizedISO8601(const std::string &date)
Creates a DateAndTime object from a date string even if the string does not exactly conform to ISO860...
MANTID_KERNEL_DLL std::string verifyAndSanitizeISO8601(const std::string &date, bool displayWarnings=true)
Verifies whether or not a string conforms to ISO8601.
MANTID_KERNEL_DLL Types::Core::DateAndTime averageSorted(const std::vector< Types::Core::DateAndTime > &times)
averageSorted Assuming that the vector is sorted, find the average time