Index: libcfa/src/time.c
===================================================================
--- libcfa/src/time.c	(revision bf71cfdb7285490eee552b461158846f626cc52f)
+++ libcfa/src/time.c	(revision bf71cfdb7285490eee552b461158846f626cc52f)
@@ -0,0 +1,161 @@
+// 
+// Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+// 
+// time.c -- 
+// 
+// Author           : Peter A. Buhr
+// Created On       : Tue Mar 27 13:33:14 2018
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Sun May  6 22:26:00 2018
+// Update Count     : 37
+// 
+
+#include "time"
+#include "iostream"
+#include <stdio.h>										// snprintf
+#include <assert.h>
+
+static char * nanomsd( long int ns, char * buf ) {		// most significant digits
+	snprintf( buf, 16, ".%09ld", ns );
+	int i;
+	for ( i = 9; buf[i] == '0' ; i -= 1 );				// find least significant digit
+	buf[i + 1] = '\0';
+	return buf;
+} // nanomsd
+
+
+//######################### Duration #########################
+
+
+forall( dtype ostype | ostream( ostype ) )
+ostype & ?|?( ostype & os, Duration dur ) with( dur ) {
+	os | tv / TIMEGRAN;									// print seconds
+	long int ns = (tv < 0 ? -tv : tv) % TIMEGRAN;		// compute nanoseconds
+	if ( ns != 0 ) {									// some ?
+		char buf[16];
+		os | nanomsd( ns, buf );						// print nanoseconds
+	} // if
+	return os;
+} // ?|?
+
+
+//######################### Time #########################
+
+
+#ifdef __CFA_DEBUG__
+#define CreateFmt "Attempt to create Time( year=%d (>=1970), month=%d (1-12), day=%d (1-31), hour=%d (0-23), min=%d (0-59), sec=%d (0-60), nsec=%d (0-999_999_999), " \
+	"which exceeds range 00:00:00 UTC, January 1, 1970 to 03:14:07 UTC, January 19, 2038."
+#endif // __CFA_DEBUG__
+
+void ?{}( Time & time, int year, int month, int day, int hour, int min, int sec, int nsec ) with( time ) {
+	tm tm;
+
+	tm.tm_isdst = -1;									// let mktime determine if alternate timezone is in effect
+	tm.tm_year = year - 1900;							// mktime uses 1900 as its starting point
+#ifdef __CFA_DEBUG__
+	if ( month < 1 || 12 < month ) {
+		abort( CreateFmt, year, month, day, hour, (int)min, sec, nsec );
+	} // if
+#endif // __CFA_DEBUG__
+	tm.tm_mon = month - 1;								// mktime uses range 0-11
+#ifdef __CFA_DEBUG__
+	if ( day < 1 || 31 < day ) {
+		abort( CreateFmt, year, month, day, hour, (int)min, sec, nsec );
+	} // if
+#endif // __CFA_DEBUG__
+	tm.tm_mday = day;									// mktime uses range 1-31
+	tm.tm_hour = hour;
+	tm.tm_min = min;
+	tm.tm_sec = sec;
+	time_t epochsec = mktime( &tm );
+#ifdef __CFA_DEBUG__
+	if ( epochsec == (time_t)-1 ) {
+		abort( CreateFmt, year, month, day, hour, (int)min, sec, nsec );
+	} // if
+#endif // __CFA_DEBUG__
+	tv = (int64_t)(epochsec) * TIMEGRAN + nsec;			// convert to nanoseconds
+#ifdef __CFA_DEBUG__
+	if ( tv > 2147483647LL * TIMEGRAN ) {				// between 00:00:00 UTC, January 1, 1970 and 03:14:07 UTC, January 19, 2038.
+		abort( CreateFmt, year, month, day, hour, (int)min, sec, nsec );
+	} // if
+#endif // __CFA_DEBUG__
+} // ?{}
+
+char * yy_mm_dd( Time time, char * buf ) with( time ) {
+	time_t s = tv / TIMEGRAN;
+	tm tm;
+	gmtime_r( &s, &tm );								// tm_mon <= 11, tm_mday <= 31
+#if defined(__GNUC__) && __GNUC__ >= 7
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-truncation"
+#endif
+	snprintf( buf, 9, "%02d/%02d/%02d", tm.tm_year % 99, tm.tm_mon + 1, tm.tm_mday );
+#if defined(__GNUC__) && __GNUC__ >= 7
+#pragma GCC diagnostic pop
+#endif
+	return buf;
+} // yy_mm_dd
+
+char * mm_dd_yy( Time time, char * buf ) with( time ) {
+	time_t s = tv / TIMEGRAN;
+	tm tm;
+	gmtime_r( &s, &tm );								// tm_mon <= 11, tm_mday <= 31
+#if defined(__GNUC__) && __GNUC__ >= 7
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-truncation"
+#endif
+	snprintf( buf, 9, "%02d/%02d/%02d", tm.tm_mon + 1, tm.tm_mday, tm.tm_year % 99 );
+#if defined(__GNUC__) && __GNUC__ >= 7
+#pragma GCC diagnostic pop
+#endif
+	return buf;
+} // mm_dd_yy
+
+char * dd_mm_yy( Time time, char * buf ) with( time ) {
+	time_t s = tv / TIMEGRAN;
+	tm tm;
+	gmtime_r( &s, &tm );								// tm_mon <= 11, tm_mday <= 31
+#if defined(__GNUC__) && __GNUC__ >= 7
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-truncation"
+#endif
+	snprintf( buf, 9, "%02d/%02d/%02d", tm.tm_mday, tm.tm_mon + 1, tm.tm_year % 99 );
+#if defined(__GNUC__) && __GNUC__ >= 7
+#pragma GCC diagnostic pop
+#endif
+	return buf;
+} // dd_mm_yy
+
+size_t strftime( char * buf, size_t size, const char * fmt, Time time ) with( time ) {
+	time_t s = tv / TIMEGRAN;
+	tm tm;
+	gmtime_r( &s, &tm );
+	return strftime( buf, size, fmt, &tm );
+} // strftime
+
+forall( dtype ostype | ostream( ostype ) )
+ostype & ?|?( ostype & os, Time time ) with( time ) {
+	char buf[32];										// at least 26
+	time_t s = tv / TIMEGRAN;
+    ctime_r( &s, (char *)&buf );						// 26 characters: "Wed Jun 30 21:49:08 1993\n"
+	buf[24] = '\0';										// remove trailing '\n'
+	long int ns = (tv < 0 ? -tv : tv) % TIMEGRAN;		// compute nanoseconds
+	if ( ns == 0 ) {									// none ?
+		os | buf;										// print date/time/year
+	} else {
+		buf[19] = '\0';									// truncate to "Wed Jun 30 21:49:08"
+		os | buf;										// print date/time
+		char buf2[16];
+		nanomsd( ns, buf2 );							// compute nanoseconds
+		os | buf2 | ' ' | &buf[20];						// print nanoseconds and year
+	} // if
+	return os;
+} // ?|?
+
+// Local Variables: //
+// mode: c //
+// tab-width: 4 //
+// End: //
