1 /** 2 * DDBC - D DataBase Connector - abstraction layer for RDBMS access, with interface similar to JDBC. 3 * 4 * Source file ddbc/drivers/mysqlddbc.d. 5 * 6 * DDBC library attempts to provide implementation independent interface to different databases. 7 * 8 * Set of supported RDBMSs can be extended by writing Drivers for particular DBs. 9 * 10 * JDBC documentation can be found here: 11 * $(LINK http://docs.oracle.com/javase/1.5.0/docs/api/java/sql/package-summary.html)$(BR) 12 * 13 * This module contains misc utility functions which may help in implementation of DDBC drivers. 14 * 15 * Copyright: Copyright 2013 16 * License: $(LINK www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 17 * Author: Vadim Lopatin 18 */ 19 module ddbc.drivers.utils; 20 21 private import std.conv : ConvException; 22 private import std.datetime : Date, DateTime, TimeOfDay; 23 private import std.datetime.date; 24 private import std.datetime.systime : SysTime; 25 private import std.datetime.timezone : UTC; 26 private import std.format : formattedRead; 27 //private import std.traits : isSomeString; 28 private import std.algorithm : canFind; 29 30 string copyCString(T)(const T* c, int actualLength = -1) if (is(T == char) || is (T == ubyte)) { 31 const(T)* a = c; 32 if(a is null) 33 return null; 34 35 if(actualLength == -1) { 36 T[] ret; 37 while(*a) { 38 ret ~= *a; 39 a++; 40 } 41 return cast(string)ret; 42 } else { 43 return cast(string)(a[0..actualLength].idup); 44 } 45 46 } 47 48 SysTime parseSysTime(const string timestampString) @safe { 49 try { 50 import std.regex : match; 51 if(match(timestampString, r"\d{4}-\D{3}-\d{2}.*")) { 52 return SysTime.fromSimpleString(timestampString); 53 } else if(match(timestampString, r".*[\+|\-]\d{1,2}:\d{1,2}|.*Z")) { 54 return timestampString.canFind('-') ? 55 SysTime.fromISOExtString(timestampString) : 56 SysTime.fromISOString(timestampString); 57 } else { 58 return SysTime(parseDateTime(timestampString), UTC()); 59 } 60 } catch (ConvException e) { 61 // static if(__traits(compiles, (){ import std.experimental.logger; } )) { 62 // import std.experimental.logger : sharedLog; 63 // sharedLog.error("Could not parse " ~ timestampString ~ " to SysTime", e); 64 // } 65 throw new DateTimeException("Can not convert '" ~ timestampString ~ "' to SysTime"); 66 } 67 } 68 69 unittest { 70 // Accept valid (as per D language) systime formats 71 parseSysTime("2019-May-04 13:34:10.500Z"); 72 parseSysTime("2019-Jan-02 13:34:10-03:00"); 73 parseSysTime("2019-05-04T13:34:10.500Z"); 74 parseSysTime("2019-06-14T13:34:10.500+01:00"); 75 parseSysTime("2019-02-07T13:34:10Z"); 76 parseSysTime("2019-08-12T13:34:10+01:00"); 77 parseSysTime("2019-09-03T13:34:10"); 78 79 // Accept valid (as per D language) date & datetime timestamps (will default timezone as UTC) 80 parseSysTime("2010-Dec-30 00:00:00"); 81 parseSysTime("2019-05-04 13:34:10"); 82 // parseSysTime("2019-05-08"); 83 84 // Accept non-standard (as per D language) timestamp formats 85 //parseSysTime("2019-05-07 13:32"); // todo: handle missing seconds 86 //parseSysTime("2019/05/07 13:32"); // todo: handle slash instead of hyphen 87 //parseSysTime("2010-12-30 12:10:04.1+00"); // postgresql 88 } 89 90 DateTime parseDateTime(const string timestampString) @safe { 91 try { 92 import std.regex : match; 93 if(match(timestampString, r"\d{8}T\d{6}")) { 94 // ISO String: 'YYYYMMDDTHHMMSS' 95 return DateTime.fromISOString(timestampString); 96 } else if(match(timestampString, r"\d{4}-\D{3}-\d{2}.*")) { 97 // Simple String 'YYYY-Mon-DD HH:MM:SS' 98 return DateTime.fromSimpleString(timestampString); 99 } else if(match(timestampString, r"\d{4}-\d{2}-\d{2}.*")) { 100 // ISO ext string 'YYYY-MM-DDTHH:MM:SS' 101 import std..string : translate; 102 return DateTime.fromISOExtString(timestampString.translate( [ ' ': 'T' ] )); 103 } 104 throw new DateTimeException("Can not convert " ~ timestampString); 105 } catch (ConvException e) { 106 // static if(__traits(compiles, (){ import std.experimental.logger; } )) { 107 // import std.experimental.logger : sharedLog; 108 // sharedLog.error("Could not parse " ~ timestampString ~ " to SysTime", e); 109 // } 110 throw new DateTimeException("Can not convert '" ~ timestampString ~ "' to DateTime"); 111 } 112 } 113 unittest { 114 // Accept valid (as per D language) datetime formats 115 parseDateTime("20101230T000000"); 116 parseDateTime("2019-May-04 13:34:10"); 117 parseDateTime("2019-Jan-02 13:34:10"); 118 parseDateTime("2019-05-04T13:34:10"); 119 120 // Accept non-standard (as per D language) timestamp formats 121 parseDateTime("2019-06-14 13:34:10"); // accept a non-standard variation (space instead of T) 122 //parseDateTime("2019-05-07 13:32"); // todo: handle missing seconds 123 //parseDateTime("2019/05/07 13:32"); // todo: handle slash instead of hyphen 124 } 125 126 TimeOfDay parseTimeoid(const string timeoid) 127 { 128 string input = timeoid.dup; 129 int hour, min, sec; 130 formattedRead(input, "%s:%s:%s", &hour, &min, &sec); 131 return TimeOfDay(hour, min, sec); 132 } 133 134 Date parseDateoid(const string dateoid) 135 { 136 string input = dateoid.dup; 137 int year, month, day; 138 formattedRead(input, "%s-%s-%s", &year, &month, &day); 139 return Date(year, month, day); 140 }