Alternative to ctime

Whenever I call ctime, I get the following error
 
Error	1	error C4996: 'ctime': This function or variable may be unsafe. Consider using ctime_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
.

I looked around the web and found the chrono library, problem with the following library is, (well at least with the tutorials that I found), it still uses ctime to get the current calender date.


Does anyone know of an alternative to the ctime library that I can use to get the current calender date and time.

I use Visual Studio 2012, in case anybody needs the info. Below is the code that I used to get the error.
1
2
3
4
5
6
7
8
9
10
11
12
int main()
{
	time_t now = time(0);

	char * dt = ctime(&now);

	cout << "Todays Date is " << dt << endl;


	system("Pause");
	return 0;
}
closed account (E0p9LyTq)
TDM-GCC 4.9.2 doesn't have a problem with ctime().

Alternatives:

http://www.cplusplus.com/reference/ctime/asctime/
http://www.cplusplus.com/reference/ctime/strftime/
Why don't you disable deprecation like the bogus error message mentions?



@FurryGuy, thanks for the links. I still get the same error though from the tutorial from the links for using the localtime.

@jlb, Because it says its unsafe...
I don't know what behavior will result if I disable the message and use it anyway. Unless you know something I don't?

Why is it bogus?
Last edited on
closed account (E0p9LyTq)
@Student555, it could be directly related to using VS. MS had a habit of not completely following earlier C/C++ standards, looks like they are doing it still.

I don't use VS, even the "free" editions.

@FurryGuy, is ctime still part of the C++ standard or has it been deprecated like the VS message claims. Because I'm getting the feeling it is only the VS compiler that won't accept its use? Other compilers accept it.

jlb claimed the message was bogus, does that mean the error has no merit?
What would the consequence be if I completely ignored the message and disabled it.
> is ctime still part of the C++ standard or has it been deprecated like the VS message claims.

std::ctime() is part of standard C++.

You may safely ignore the warning: 'ctime': This function or variable may be unsafe. Consider using ctime_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS.

Build with _CRT_SECURE_NO_WARNINGS defined and these irritating warnings will go away.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#define _CRT_SECURE_NO_WARNINGS
#include <ctime>
#include <iostream>

int main()
{
	std::time_t now = std::time(0);

	const char * dt = std::ctime(&now);

	std::cout << "Todays Date is " << dt << '\n' ;


	//system("Pause");
	//return 0;
}


> MS had a habit of not completely following earlier C/C++ standards

This is palpably untrue. MS has a habit of not following later/current C standards. They strive very hard to conform to the C++ standard.
http://www.cplusplus.com/forum/general/145334/#msg765455

Visual Studio 2015 is an excellent C++ implementation; but it is a poor C implementation.
Our immediate and long-term goal is to fully support the C subsets of ISO C++.
If you really need either of the following:
features in C95/C99/C11 that are not part of ISO C++; or
features in C that are in the C++ subset but without also enabling the writing of C++ code;
then we recommend that you consider using a different compiler
Many old functions are deprecated by Microsoft, and often rightly so.

The ctime() function is not reentrant, which is why MS created a version that is.


Well, I was going to suggest you use the put_time manipulator, which is really just a wrapper for strftime(), but neither seem to work in GCC. (Madness!)

I don't know what else to suggest ATM, besides doing it yourself.
Thanks JLborges.

Is there a difference between adding to the cpp file as
 
#define _CRT_SECURE_NO_WARNINGS 


or placing it in
Project -> Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions

@Duoas, are you aware of any consequences that occur if ctime is used in VS 2012? Despite the warning.
Last edited on
> neither seem to work in GCC. (Madness!)

Most (if not all) of the C++11 format specifiers don't work in any of the MinGW or CygWin builds of libstdc++.
The pre-C++11 format specifiers do appear to work as expected with MinGW, GCC 5.1.

Most (may be all) of the C++11 format specifiers do work with libstdc++, GCC 5.1 on other platforms,
and with the Microsoft library on Windows.

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <iomanip>
#include <ctime>

int main()
{
    std::time_t time = std::time(nullptr);
    const std::tm tm = *std::localtime( std::addressof(time) );
    
    std::cout << "%T : " << std::put_time( std::addressof(tm), "%T" ) << '\n'; // C++11 format specifier: does not work with g++ MinGW
    std::cout << "%D : " << std::put_time( std::addressof(tm), "%D" ) << '\n'; // C++11 format specifier: does not work with g++ MinGW
    std::cout << "%c : " << std::put_time( std::addressof(tm), "%c" ) << '\n'; // classic format specifier: fine with g++ MinGW
}

http://coliru.stacked-crooked.com/a/3b580777af5b2155
Last edited on
> Is there a difference between adding to the cpp file as #define _CRT_SECURE_NO_WARNINGS
> or placing it in Project -> Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions

Placing a #define _CRT_SECURE_NO_WARNINGS before any other #include directives in the cpp file affects only that one translation unit. (Assuming that pre-compiled headers are not being used).

Placing it in Project -> Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions would make _CRT_SECURE_NO_WARNINGS effective for every translation unit (even if pre-compiled headers are used.)
This is the recommended procedure.


> any consequences that occur if ctime is used in VS 2012? Despite the warning.

This function returns a pointer to static data and is not thread-safe. In addition, it modifies the static std::tm object which may be shared with std::gmtime and std::localtime. POSIX marks this function obsolete and recommends std::strftime instead.

The behavior may be undefined for the values of time_t that result in the string longer than 25 characters (e.g. year 10000) http://en.cppreference.com/w/cpp/chrono/c/ctime

http://en.cppreference.com/w/cpp/chrono/c/strftime

The Microsoft warning would have been considered reasonable, had they recommended using another standard C++ function, instead of peddling the non-standard alternative ctime_s().
strftime() is as broken as put_time() -- the latter is a manipulator version of the former.

And, AFAICK, there aren't any complete implementations of the standard.

I'm not a fan of Microsoft's playing their own C standards, but they were right. ctime_s() is superior to ctime() for the simple fact that it is reentrant. The C11 version muddles it some, but if used properly, is also reentrant. And since it is C11, everyone should have it.

Meaning there is no good reason not to use it.
strftime() is as broken as put_time()

strftime works on MinGW GCC 4.9 if you will stay away from format specificators added in C++11

Following should work:
1
2
3
4
5
6
7
8
9
10
11
#include<iostream>
#include<ctime>

int main()
{
	char buffer[64];
	auto t = std::time(nullptr);
	auto foo = *std::localtime(&t);
	std::strftime(buffer, 64, "%Y-%m-%d %H:%M:%S", &foo);
	std::cout << buffer;
}

"%F %T" does not.
And since it is C11, everyone should have it.


Only if the compiler vendors support this optional feature. Can you tell me of a C11 standard compliant compiler that supports these optional constructs?

But since we're talking about C++ are those optional C11 features even part of the C++ standard? I don't see them in the table of Standard C functions included in the C++ standard (table 153 in annex C).

> are those optional C11 features even part of the C++ standard?
> I don't see them in the table of Standard C functions included in the C++ standard (table 153 in annex C).

ctime_s() is not standard C++. It is also not there in the current working draft for C++17.

1.2 Normative references makes it clear that the C part of the C++ standard is based on (a subset of) C99 (plus Technical Corrigenda for C99, the last of which was in 2007).

ctime_s() is not even required to be there in a fully conforming C11 implementation.
Thank you for the confirmation.

The fact that these functions are optional in C11, non-existant in C++ (any version) is one of the reasons why I consider the warning/error message being generated by the Microsoft compiler to be bogus. These non-safe functions, with the exception of gets(), are not depreciated in any version of the C or C++ standards.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// required magic!
#define __STDC_WANT_LIB_EXT1__ 1

#include <ctime>
#include <iostream>

int main()
{
  char s[ 50 ];
  std::time_t  t = std::time( NULL );
  errno_t e = ctime_s( s, 50, &t );
  if (e) std::cout << "fooey!\n";
  else   std::cout << s;
}  
Thu Aug 06 15:02:02 2015

Tested with
- GCC 5.1.0
- Microsoft C/C++ 2012

ISO/IEC 9899:2011 K.2/1 states:
This annex specifies a series of optional extensions that can be useful in the mitigation of security vulnerabilities in programs, and comprise new functions, macros, and types declared or defined in existing standard headers.
 
ISO/IEC 9899:2011 K.3.8.2.2/1 states:
1
2
3
#define __STDC_WANT_LIB_EXT1_ _ 1
#include <time.h>
errno_t ctime_s(char *s, rsize_t maxsize, const time_t *timer);

Optional or not, the two major players have it. There is no excuse.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// required magic!
#define __STDC_WANT_LIB_EXT1__ 1

#include <ctime>
#include <iostream>

int main()
{
    char s[50];
    std::time_t  t = std::time( NULL );
    int e ; // int e instead of errno_t e to avoid the error: errno_t was not declared
    e = ctime_s( s, 50, &t ); // *** error: 'ctime_s' was not declared in this scope                             // 
    if( e ) std::cout << "fooey!\n";
    else   std::cout << s;
}

C++ (g++), strict C++ conformance
g++ --version | grep GCC && g++ -std=c++14 -O3 -Wall -Wextra -pedantic-errors -c main.cpp
g++ (GCC) 5.2.0
main.cpp: In function 'int main()':
main.cpp:12:28: error: 'ctime_s' was not declared in this scope
     e = ctime_s( s, 50, &t ); // *** error: 'ctime_s' was not declared in this scope  

http://coliru.stacked-crooked.com/a/04d36baddc3446be


C++ (g++), GNU dialect of C++14, no strict C++ conformance
g++ --version | grep GCC && g++ -std=gnu++14 -Wall -Wextra  -c main.cpp
g++ (GCC) 5.2.0
main.cpp: In function 'int main()':
main.cpp:12:28: error: 'ctime_s' was not declared in this scope
     e = ctime_s( s, 50, &t ); // *** error: 'ctime_s' was not declared in this scope 

http://coliru.stacked-crooked.com/a/4fa620aba6532043


C++ (g++), GNU default, no strict C++ conformance
g++ --version | grep GCC && g++ -O3 -Wall -Wextra -c main.cpp
g++ (GCC) 5.2.0
main.cpp: In function 'int main()':
main.cpp:12:28: error: 'ctime_s' was not declared in this scope
     e = ctime_s( s, 50, &t ); // *** error: 'ctime_s' was not declared in this scope

http://coliru.stacked-crooked.com/a/085f7aff559ad4b9

GCC 5.1 (g++) issues the same errors
http://coliru.stacked-crooked.com/a/fce8993f6cffd3ca
http://coliru.stacked-crooked.com/a/27bf6b53d6385f00
http://coliru.stacked-crooked.com/a/a0ca709586b57318


C (gcc) std=c11
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// required magic!
#define __STDC_WANT_LIB_EXT1__ 1

#include <time.h>
#include <stdio.h>

int main()
{
    char s[50];
    time_t  t = time( NULL );
    int e ; // int e instead of errno_t e to avoid the error: errno_t was not declared
    e = ctime_s( s, 50, &t );                           // 
    if( e ) puts( "fooey!" ) ;
    else puts(s);
}

gcc --version | grep GCC && gcc -std=c11 -O3 -Wall -Wextra -x c main.cpp && ./a.out
gcc (GCC) 5.2.0
main.cpp: In function 'main':
main.cpp:12:9: warning: implicit declaration of function 'ctime_s' [-Wimplicit-function-declaration]
     e = ctime_s( s, 50, &t );                           // 
         ^
/tmp/ccqJAS5o.o: In function `main':
main.cpp:(.text.startup+0x22): undefined reference to `ctime_s'
collect2: error: ld returned 1 exit status

http://coliru.stacked-crooked.com/a/5dfead606590baeb

There is no excuse for using ::ctime_s() in C++;
when std::strftime() with a format specifier of "%c" is part of standard C++ (and it is available everywhere.)
I yield.
[I was wrong.]
Topic archived. No new replies allowed.