2
\$\begingroup\$

I am working on a utility function to get the current date and time. My objective is to do this in a generic and portable way. I would like to stay way from platform specific code to allow the functionally of this method to be portable.

I had originally asked a question over at Stack Overflow followed up by another question.

The question(s) that I had asked in the former Stack Overflow Q/A is more relevant that the first in regards to this question or set of questions.


Here is the code that I had written to get the current date and time:

DateAndTime.h

#pragma once

#include <ctime> 
#include <iomanip>
#include <iostream>
#include <sstream>

namespace util {

    enum class TimeLocale {
        LOCAL = 0x01,
        GMT = 0x02,
        BOTH = (LOCAL | GMT)
    };  

    inline TimeLocale operator|(TimeLocale a, TimeLocale b) {
        return static_cast<TimeLocale>(static_cast<int>(a) | static_cast<int>(b));
    }

#pragma warning( push )
#pragma warning( disable : 4996 )
    inline void currentDateAndTime(std::stringstream& stream, TimeLocale locale) {
        std::time_t t = std::time(nullptr);

        if (locale == TimeLocale::GMT) {
            stream << "UTC:   " << std::put_time(std::gmtime(&t), "%c, %Z") << '\n';
        }

        if (locale == TimeLocale::LOCAL) {
            stream << "LOCAL: " << std::put_time(std::localtime(&t), "%c, %Z") << '\n';
        }

        if (locale == TimeLocale::BOTH) {
            stream << "UTC:   " << std::put_time(std::gmtime(&t), "%c, %Z") << '\n'
                   << "LOCAL: " << std::put_time(std::localtime(&t), "%c, %Z") << '\n';
        }
    }
#pragma warning( pop )

} // namespace util

main.cpp

#include "DateAndTime.h"

#include <ctime>
#include <exception>
#include <iomanip>
#include <iostream>

using namespace util;

int main() {
    try {
        std::stringstream stream1;
        currentDateAndTime(stream1, TimeLocale::GMT);
        std::cout << stream1.str() << '\n';

        std::stringstream stream2;
        currentDateAndTime(stream2, TimeLocale::LOCAL);
        std::cout << stream2.str() << '\n';

        std::stringstream stream3;
        currentDateAndTime(stream3, TimeLocale::BOTH);
        std::cout << stream3.str() << '\n';

        std::stringstream stream4;
        currentDateAndTime(stream4, TimeLocale::GMT | TimeLocale::LOCAL);
        std::cout << stream4.str() << '\n';    

    } catch ( const std::exception& e ) {
        std::cout << "Exception Thrown: " << e.what() << std::endl;
        return EXIT_FAILURE;
    } catch (...) {
        std::cout << __FUNCTION__ << " Caught Unknown Exception" << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

And the above code would generate a nicely formatted possible result:

UTC:   02/20/19 05:44:38, Eastern Standard Time

Local: 02/20/19 00:44:38, Eastern Standard Time

UTC:   02/20/19 05:44:38, Eastern Standard Time
Local: 02/20/19 00:44:38, Eastern Standard Time

UTC:   02/20/19 05:44:38, Eastern Standard Time
Local: 02/20/19 00:44:38, Eastern Standard Time

Currently as it stands, this is acceptable for me considering my current situation. I'm not quite able to use the new features that can be found in <std::chrono> for its calendar resources, as I'm stuck with Visual Studio 2017 and C++17.


There are a few things that I would like to know about the above function and its functionality.

  • Other than using library functions that have been marked deprecated such as std::gmtime and std::localtime and having to suppress the compiler warning, is the overall above code considered good design, and is it considered readable and reliable?
  • Is there anything that could be done to improve this: Are there any corner case errors that I may have missed, can this be made more efficient.
  • Would this above code be considered portable, cross-platform?

The last thing I would like to know are there any other standard ways to achieve this through the standard library without using platform specific code?


I wouldn't mind using chrono but its newer features are not quite yet available; and I don't want to use any third party libraries like boost for example.

I am aware of the fact that different operating systems as well as different hardware (processors) retrieve and calculate the current time differently, and that different regions have different types of calendars and time zone formats.

Above are some of the reasons that made it a formidable challenge to retrieve the current date and time using only standard C++. I might just have to wait for the release of Visual Studio 2019 for C++20 to arrive.

I'm looking forward to any and all feedback.

\$\endgroup\$
6
  • \$\begingroup\$ What's "deprecated" about the <ctime> functions? I don't think there's any proposal to remove them in the C++20 timeframe, or even beyond. \$\endgroup\$ Commented Feb 20, 2019 at 11:30
  • \$\begingroup\$ @TobySpeight With my current IDE & Compiler Visual Studio 2017 using c++ latest draft standard which should be C++17; if I remove the #pragma warning(push) #pragma warning(disable : 4996) #pragma warning(pop) away from the currentDateAndTime(...) function my compiler yells at me that std::gmtime and std::localtime are not considered safe and that they have been marked for deprecation. \$\endgroup\$ Commented Feb 20, 2019 at 12:25
  • \$\begingroup\$ @TobySpeight I'm thinking they might be marked as deprecated because of the std::chrono calendar features that will be added to the standard come C++20 in Visual Studio 2019 and or other compilers that will support C++20 when it is officially released. \$\endgroup\$ Commented Feb 20, 2019 at 12:27
  • \$\begingroup\$ Sounds like one vendor's opinion, rather than a Standard statement. Perhaps they're suggesting that you'd want gmtime_r() and the like, or their platform's equivalent. But if you're writing a single-threaded program, there's no need to panic! \$\endgroup\$ Commented Feb 20, 2019 at 12:39
  • 1
    \$\begingroup\$ @FrancisCugler In case you don't know, you can look at this for an up-to-date C++ standard draft if you don't own a copy of the standard. Should suffice for most cases :) \$\endgroup\$
    – L. F.
    Commented Feb 20, 2019 at 13:01

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.