181b81b4a4
Former-commit-id: cf92446697332992ec36726e78eb8703e1f259d7
674 lines
17 KiB
C#
674 lines
17 KiB
C#
//
|
|
// OciDefineHandle.cs
|
|
//
|
|
// Part of managed C#/.NET library System.Data.OracleClient.dll
|
|
//
|
|
// Part of the Mono class libraries at
|
|
// mcs/class/System.Data.OracleClient/System.Data.OracleClient.Oci
|
|
//
|
|
// Assembly: System.Data.OracleClient.dll
|
|
// Namespace: System.Data.OracleClient.Oci
|
|
//
|
|
// Authors:
|
|
// Tim Coleman <tim@timcoleman.com>
|
|
// Daniel Morgan <monodanmorg@yahoo.com>
|
|
//
|
|
// Copyright (C) Tim Coleman, 2003
|
|
// Copyright (C) Daniel Morgan, 2004, 2009
|
|
//
|
|
|
|
using System;
|
|
using System.Data.OracleClient;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
|
|
namespace System.Data.OracleClient.Oci
|
|
{
|
|
internal sealed class OciDefineHandle : OciHandle, IDisposable
|
|
{
|
|
#region Fields
|
|
|
|
bool disposed = false;
|
|
|
|
//IntPtr handle;
|
|
IntPtr value;
|
|
IntPtr indicator;
|
|
//OracleType type;
|
|
OciDataType ociType;
|
|
OciDataType definedType;
|
|
int definedSize;
|
|
IntPtr rlenp;
|
|
//short precision;
|
|
short scale;
|
|
Type fieldType;
|
|
string name;
|
|
|
|
// Oracle defines the LONG VARCHAR and LONG VARRAW to have a size of 2 to the 31 power - 5
|
|
// see DefineLongVarChar and DefineLongVarRaw
|
|
// TODO: see OCI Programmers Guide on how to do a piece-wise operations
|
|
// instead of using the below. Or better yet, convert
|
|
// your LONG/LONG VARCHAR to CLOB and LONG RAW/LONG VARRAW to BLOB.
|
|
internal static int LongVarCharMaxValue = (int) Int16.MaxValue - 5;
|
|
internal static int LongVarRawMaxValue = (int) Int16.MaxValue - 5;
|
|
|
|
OciErrorHandle errorHandle;
|
|
|
|
OciLobLocator lobLocator;
|
|
OciDateTimeDescriptor dateTimeDesc;
|
|
OciIntervalDescriptor intervalDesc;
|
|
|
|
#endregion // Fields
|
|
|
|
#region Constructors
|
|
|
|
internal OciDefineHandle (OciHandle parent, IntPtr newHandle)
|
|
: base (OciHandleType.Define, parent, newHandle)
|
|
{
|
|
}
|
|
|
|
internal void DefineByPosition (int position, OracleConnection connection)
|
|
{
|
|
OciParameterDescriptor parameter = ((OciStatementHandle) Parent).GetParameter (position);
|
|
|
|
name = parameter.GetName ();
|
|
definedType = parameter.GetDataType ();
|
|
definedSize = parameter.GetDataSize ();
|
|
//precision = parameter.GetPrecision ();
|
|
scale = parameter.GetScale ();
|
|
rlenp = OciCalls.AllocateClear (sizeof(short));
|
|
indicator = OciCalls.AllocateClear (sizeof(short));
|
|
|
|
Define (position, connection);
|
|
|
|
parameter.Dispose ();
|
|
}
|
|
|
|
#endregion // Constructors
|
|
|
|
#region Properties
|
|
|
|
internal OciDataType DataType {
|
|
get { return definedType; }
|
|
}
|
|
|
|
internal Type FieldType {
|
|
get { return fieldType; }
|
|
}
|
|
|
|
internal int DefinedSize {
|
|
get { return definedSize; }
|
|
}
|
|
|
|
internal OciErrorHandle ErrorHandle {
|
|
get { return errorHandle; }
|
|
set { errorHandle = value; }
|
|
}
|
|
|
|
internal bool IsNull {
|
|
get { return (Indicator == -1); }
|
|
}
|
|
|
|
internal short Scale {
|
|
get { return scale; }
|
|
}
|
|
|
|
internal short Size {
|
|
get { return(Marshal.ReadInt16(rlenp)); }
|
|
set { Marshal.WriteInt16(rlenp, value); }
|
|
}
|
|
|
|
internal short Indicator {
|
|
get { return(Marshal.ReadInt16(indicator)); }
|
|
set { Marshal.WriteInt16(indicator, value); }
|
|
}
|
|
|
|
internal IntPtr Value {
|
|
get { return value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
void Define (int position, OracleConnection connection)
|
|
{
|
|
switch (definedType) {
|
|
case OciDataType.Date:
|
|
DefineDate (position, connection);
|
|
return;
|
|
case OciDataType.TimeStamp:
|
|
DefineTimeStamp (position, connection);
|
|
return;
|
|
case OciDataType.Clob:
|
|
case OciDataType.Blob:
|
|
DefineLob (position, definedType, connection);
|
|
return;
|
|
case OciDataType.Raw:
|
|
case OciDataType.VarRaw:
|
|
DefineRaw( position, connection);
|
|
return;
|
|
case OciDataType.LongRaw:
|
|
case OciDataType.LongVarRaw:
|
|
DefineLongVarRaw (position, connection);
|
|
return;
|
|
case OciDataType.RowIdDescriptor:
|
|
definedSize = 10;
|
|
DefineChar (position, connection);
|
|
return;
|
|
case OciDataType.Integer:
|
|
case OciDataType.Number:
|
|
case OciDataType.Float:
|
|
case OciDataType.VarNum:
|
|
case OciDataType.UnsignedInt:
|
|
DefineNumber (position, connection);
|
|
return;
|
|
case OciDataType.Long:
|
|
case OciDataType.LongVarChar:
|
|
DefineLongVarChar (position, connection);
|
|
return;
|
|
case OciDataType.IntervalDayToSecond:
|
|
case OciDataType.IntervalYearToMonth:
|
|
DefineInterval (position, definedType, connection);
|
|
return;
|
|
default:
|
|
DefineChar (position, connection); // HANDLE ALL OTHERS AS CHAR FOR NOW
|
|
return;
|
|
}
|
|
}
|
|
|
|
void DefineTimeStamp (int position, OracleConnection connection)
|
|
{
|
|
definedSize = -1;
|
|
ociType = OciDataType.TimeStamp;
|
|
fieldType = typeof(System.DateTime);
|
|
|
|
dateTimeDesc = (OciDateTimeDescriptor) connection.Environment.Allocate (OciHandleType.TimeStamp);
|
|
if (dateTimeDesc == null) {
|
|
OciErrorInfo info = connection.ErrorHandle.HandleError ();
|
|
throw new OracleException (info.ErrorCode, info.ErrorMessage);
|
|
}
|
|
|
|
value = dateTimeDesc.Handle;
|
|
dateTimeDesc.ErrorHandle = ErrorHandle;
|
|
|
|
int status = 0;
|
|
|
|
status = OciCalls.OCIDefineByPosPtr (Parent,
|
|
out handle,
|
|
ErrorHandle,
|
|
position + 1,
|
|
ref value,
|
|
definedSize,
|
|
ociType,
|
|
indicator,
|
|
rlenp,
|
|
IntPtr.Zero,
|
|
0);
|
|
|
|
definedSize = 11;
|
|
|
|
if (status != 0) {
|
|
OciErrorInfo info = connection.ErrorHandle.HandleError ();
|
|
throw new OracleException (info.ErrorCode, info.ErrorMessage);
|
|
}
|
|
}
|
|
|
|
void DefineDate (int position, OracleConnection connection)
|
|
{
|
|
definedSize = 7;
|
|
ociType = OciDataType.Date;
|
|
fieldType = typeof(System.DateTime);
|
|
|
|
value = OciCalls.AllocateClear (definedSize);
|
|
|
|
int status = 0;
|
|
|
|
status = OciCalls.OCIDefineByPos (Parent,
|
|
out handle,
|
|
ErrorHandle,
|
|
position + 1,
|
|
value,
|
|
definedSize,
|
|
ociType,
|
|
indicator,
|
|
rlenp,
|
|
IntPtr.Zero,
|
|
0);
|
|
|
|
if (status != 0) {
|
|
OciErrorInfo info = ErrorHandle.HandleError ();
|
|
throw new OracleException (info.ErrorCode, info.ErrorMessage);
|
|
}
|
|
}
|
|
|
|
void DefineLongVarChar (int position, OracleConnection connection)
|
|
{
|
|
fieldType = typeof (System.String);
|
|
|
|
// LONG VARCHAR max length is 2 to the 31 power - 5
|
|
// the first 4 bytes of a LONG VARCHAR value contains the length
|
|
// Int32.MaxValue - 5 causes out of memory in mono on win32
|
|
// because I do not have 2GB of memory available
|
|
// so Int16.MaxValue - 5 is used instead.
|
|
// LAMESPEC for Oracle OCI - you can not get the length of the LONG VARCHAR value
|
|
// until after you get the value. This could be why Oracle deprecated LONG VARCHAR.
|
|
// If you specify a definedSize less then the length of the column value,
|
|
// then you will get an OCI_ERROR ORA-01406: fetched column value was truncated
|
|
|
|
// TODO: get via piece-wise - a chunk at a time
|
|
definedSize = LongVarCharMaxValue;
|
|
|
|
value = OciCalls.AllocateClear (definedSize);
|
|
ociType = OciDataType.LongVarChar;
|
|
|
|
int status = 0;
|
|
status = OciCalls.OCIDefineByPos (Parent,
|
|
out handle,
|
|
ErrorHandle,
|
|
position + 1,
|
|
value,
|
|
definedSize,
|
|
ociType,
|
|
indicator,
|
|
rlenp,
|
|
IntPtr.Zero, 0);
|
|
|
|
Size = (short) definedSize;
|
|
|
|
if (status != 0) {
|
|
OciErrorInfo info = ErrorHandle.HandleError ();
|
|
throw new OracleException (info.ErrorCode, info.ErrorMessage);
|
|
}
|
|
}
|
|
|
|
void DefineChar (int position, OracleConnection connection)
|
|
{
|
|
fieldType = typeof (System.String);
|
|
|
|
int maxByteCount = Encoding.UTF8.GetMaxByteCount (definedSize);
|
|
value = OciCalls.AllocateClear (maxByteCount);
|
|
|
|
ociType = OciDataType.Char;
|
|
|
|
int status = 0;
|
|
|
|
status = OciCalls.OCIDefineByPos (Parent,
|
|
out handle,
|
|
ErrorHandle,
|
|
position + 1,
|
|
value,
|
|
maxByteCount,
|
|
ociType,
|
|
indicator,
|
|
rlenp,
|
|
IntPtr.Zero,
|
|
0);
|
|
OciErrorHandle.ThrowExceptionIfError (ErrorHandle, status);
|
|
}
|
|
|
|
void DefineNumber (int position, OracleConnection connection)
|
|
{
|
|
fieldType = typeof (System.Decimal);
|
|
value = OciCalls.AllocateClear (definedSize);
|
|
|
|
ociType = OciDataType.Char;
|
|
|
|
int status = 0;
|
|
|
|
status = OciCalls.OCIDefineByPos (Parent,
|
|
out handle,
|
|
ErrorHandle,
|
|
position + 1,
|
|
value,
|
|
definedSize,
|
|
ociType,
|
|
indicator,
|
|
rlenp,
|
|
IntPtr.Zero,
|
|
0);
|
|
|
|
if (status != 0) {
|
|
OciErrorInfo info = ErrorHandle.HandleError ();
|
|
throw new OracleException (info.ErrorCode, info.ErrorMessage);
|
|
}
|
|
}
|
|
|
|
void DefineLob (int position, OciDataType type, OracleConnection connection)
|
|
{
|
|
ociType = type;
|
|
|
|
if (ociType == OciDataType.Clob)
|
|
fieldType = typeof(System.String);
|
|
else if (ociType == OciDataType.Blob)
|
|
fieldType = typeof(byte[]);
|
|
|
|
int status = 0;
|
|
|
|
definedSize = -1;
|
|
|
|
lobLocator = (OciLobLocator) connection.Environment.Allocate (OciHandleType.LobLocator);
|
|
|
|
if (lobLocator == null) {
|
|
OciErrorInfo info = connection.ErrorHandle.HandleError ();
|
|
throw new OracleException (info.ErrorCode, info.ErrorMessage);
|
|
}
|
|
|
|
value = lobLocator.Handle;
|
|
lobLocator.ErrorHandle = connection.ErrorHandle;
|
|
lobLocator.Service = connection.ServiceContext;
|
|
lobLocator.Environment = connection.Environment;
|
|
|
|
status = OciCalls.OCIDefineByPosPtr (Parent,
|
|
out handle,
|
|
ErrorHandle,
|
|
position + 1,
|
|
ref value,
|
|
definedSize,
|
|
ociType,
|
|
indicator,
|
|
rlenp,
|
|
IntPtr.Zero,
|
|
0);
|
|
|
|
definedSize = Int32.MaxValue;
|
|
|
|
if (status != 0) {
|
|
OciErrorInfo info = connection.ErrorHandle.HandleError ();
|
|
throw new OracleException (info.ErrorCode, info.ErrorMessage);
|
|
}
|
|
}
|
|
|
|
void DefineRaw (int position, OracleConnection connection)
|
|
{
|
|
ociType = OciDataType.Raw;
|
|
fieldType = typeof (byte[]);
|
|
|
|
value = OciCalls.AllocateClear (definedSize);
|
|
|
|
int status = 0;
|
|
|
|
status = OciCalls.OCIDefineByPos (Parent,
|
|
out handle,
|
|
ErrorHandle,
|
|
position + 1,
|
|
value,
|
|
definedSize,
|
|
ociType,
|
|
indicator,
|
|
rlenp,
|
|
IntPtr.Zero, 0);
|
|
|
|
if (status != 0) {
|
|
OciErrorInfo info = ErrorHandle.HandleError ();
|
|
throw new OracleException (info.ErrorCode, info.ErrorMessage);
|
|
}
|
|
}
|
|
|
|
void DefineLongVarRaw (int position, OracleConnection connection)
|
|
{
|
|
ociType = OciDataType.LongVarRaw;
|
|
fieldType = typeof (byte[]);
|
|
|
|
// TODO: get via piece-wise - a chunk at a time
|
|
definedSize = LongVarRawMaxValue;
|
|
|
|
value = OciCalls.AllocateClear (definedSize);
|
|
|
|
int status = 0;
|
|
|
|
status = OciCalls.OCIDefineByPos (Parent,
|
|
out handle,
|
|
ErrorHandle,
|
|
position + 1,
|
|
value,
|
|
definedSize,
|
|
ociType,
|
|
indicator,
|
|
rlenp,
|
|
IntPtr.Zero, 0);
|
|
|
|
if (status != 0) {
|
|
OciErrorInfo info = ErrorHandle.HandleError ();
|
|
throw new OracleException (info.ErrorCode, info.ErrorMessage);
|
|
}
|
|
}
|
|
|
|
void DefineInterval (int position, OciDataType type, OracleConnection connection)
|
|
{
|
|
ociType = type;
|
|
fieldType = typeof(string);
|
|
definedSize = -1;
|
|
|
|
switch (type) {
|
|
case OciDataType.IntervalDayToSecond:
|
|
definedSize = 11;
|
|
intervalDesc = (OciIntervalDescriptor) connection.Environment.Allocate (OciHandleType.IntervalDayToSecond);
|
|
break;
|
|
case OciDataType.IntervalYearToMonth:
|
|
intervalDesc = (OciIntervalDescriptor) connection.Environment.Allocate (OciHandleType.IntervalYearToMonth);
|
|
definedSize = 5;
|
|
break;
|
|
}
|
|
|
|
if (intervalDesc == null) {
|
|
OciErrorInfo info = connection.ErrorHandle.HandleError ();
|
|
throw new OracleException (info.ErrorCode, info.ErrorMessage);
|
|
}
|
|
|
|
value = intervalDesc.Handle;
|
|
intervalDesc.ErrorHandle = ErrorHandle;
|
|
|
|
int status = 0;
|
|
|
|
status = OciCalls.OCIDefineByPosPtr (Parent,
|
|
out handle,
|
|
ErrorHandle,
|
|
position + 1,
|
|
ref value,
|
|
definedSize,
|
|
ociType,
|
|
indicator,
|
|
rlenp,
|
|
IntPtr.Zero,
|
|
0);
|
|
|
|
if (status != 0) {
|
|
OciErrorInfo info = connection.ErrorHandle.HandleError ();
|
|
throw new OracleException (info.ErrorCode, info.ErrorMessage);
|
|
}
|
|
}
|
|
|
|
protected override void Dispose (bool disposing)
|
|
{
|
|
if (!disposed) {
|
|
try {
|
|
switch (definedType) {
|
|
case OciDataType.Clob:
|
|
case OciDataType.Blob:
|
|
case OciDataType.TimeStamp:
|
|
case OciDataType.IntervalDayToSecond:
|
|
case OciDataType.IntervalYearToMonth:
|
|
break;
|
|
default:
|
|
Marshal.FreeHGlobal (value);
|
|
break;
|
|
}
|
|
disposed = true;
|
|
} finally {
|
|
Marshal.FreeHGlobal (indicator);
|
|
Marshal.FreeHGlobal (rlenp);
|
|
base.Dispose (disposing);
|
|
value = IntPtr.Zero;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal OracleLob GetOracleLob ()
|
|
{
|
|
return new OracleLob (lobLocator, ociType);
|
|
}
|
|
|
|
internal object GetValue (IFormatProvider formatProvider, OracleConnection conn)
|
|
{
|
|
object tmp;
|
|
|
|
byte [] buffer = null;
|
|
|
|
switch (DataType) {
|
|
case OciDataType.VarChar2:
|
|
case OciDataType.String:
|
|
case OciDataType.VarChar:
|
|
case OciDataType.Char:
|
|
case OciDataType.CharZ:
|
|
case OciDataType.OciString:
|
|
case OciDataType.RowIdDescriptor:
|
|
buffer = new byte [Size];
|
|
Marshal.Copy (Value, buffer, 0, Size);
|
|
|
|
// Get length of returned string
|
|
int rsize = 0;
|
|
//IntPtr env = Parent.Parent; // Parent is statement, grandparent is environment
|
|
IntPtr env = conn.Environment;
|
|
int status = OciCalls.OCICharSetToUnicode (env, null, buffer, out rsize);
|
|
OciErrorHandle.ThrowExceptionIfError (ErrorHandle, status);
|
|
|
|
// Get string
|
|
StringBuilder ret = new StringBuilder(rsize);
|
|
status = OciCalls.OCICharSetToUnicode (env, ret, buffer, out rsize);
|
|
OciErrorHandle.ThrowExceptionIfError (ErrorHandle, status);
|
|
|
|
return ret.ToString ();
|
|
case OciDataType.LongVarChar:
|
|
case OciDataType.Long:
|
|
buffer = new byte [LongVarCharMaxValue];
|
|
Marshal.Copy (Value, buffer, 0, buffer.Length);
|
|
|
|
int longSize = 0;
|
|
if (BitConverter.IsLittleEndian)
|
|
longSize = BitConverter.ToInt32 (new byte[]{buffer[0], buffer[1], buffer[2], buffer[3]}, 0);
|
|
else
|
|
longSize = BitConverter.ToInt32 (new byte[]{buffer[3], buffer[2], buffer[1], buffer[0]}, 0);
|
|
|
|
ASCIIEncoding encoding = new ASCIIEncoding ();
|
|
string e = encoding.GetString (buffer, 4, longSize);
|
|
return e;
|
|
case OciDataType.Integer:
|
|
case OciDataType.Number:
|
|
case OciDataType.Float:
|
|
case OciDataType.VarNum:
|
|
case OciDataType.UnsignedInt:
|
|
tmp = Marshal.PtrToStringAnsi (Value, Size);
|
|
if (tmp != null)
|
|
return Decimal.Parse (String.Copy ((string) tmp), formatProvider);
|
|
break;
|
|
case OciDataType.TimeStamp:
|
|
return dateTimeDesc.GetDateTime (conn.Environment, dateTimeDesc.ErrorHandle);
|
|
case OciDataType.Date:
|
|
return UnpackDate ();
|
|
case OciDataType.Raw:
|
|
case OciDataType.VarRaw:
|
|
byte [] raw_buffer = new byte [Size];
|
|
Marshal.Copy (Value, raw_buffer, 0, Size);
|
|
return raw_buffer;
|
|
case OciDataType.LongRaw:
|
|
case OciDataType.LongVarRaw:
|
|
buffer = new byte [LongVarRawMaxValue];
|
|
Marshal.Copy (Value, buffer, 0, buffer.Length);
|
|
|
|
int longrawSize = 0;
|
|
if (BitConverter.IsLittleEndian)
|
|
longrawSize = BitConverter.ToInt32 (new byte[]{buffer[0], buffer[1], buffer[2], buffer[3]}, 0);
|
|
else
|
|
longrawSize = BitConverter.ToInt32 (new byte[]{buffer[3], buffer[2], buffer[1], buffer[0]}, 0);
|
|
|
|
byte[] longraw_buffer = new byte [longrawSize];
|
|
Array.ConstrainedCopy (buffer, 4, longraw_buffer, 0, longrawSize);
|
|
return longraw_buffer;
|
|
case OciDataType.Blob:
|
|
case OciDataType.Clob:
|
|
return GetOracleLob ();
|
|
case OciDataType.IntervalDayToSecond:
|
|
return new OracleTimeSpan (intervalDesc.GetDayToSecond (conn.Environment, intervalDesc.ErrorHandle));
|
|
case OciDataType.IntervalYearToMonth:
|
|
return new OracleMonthSpan (intervalDesc.GetYearToMonth (conn.Environment, intervalDesc.ErrorHandle));
|
|
default:
|
|
throw new Exception("OciDataType not implemented: " + DataType.ToString ());
|
|
}
|
|
|
|
return DBNull.Value;
|
|
}
|
|
|
|
internal object GetOracleValue (IFormatProvider formatProvider, OracleConnection conn)
|
|
{
|
|
object ovalue = GetValue (formatProvider, conn);
|
|
|
|
switch (DataType) {
|
|
case OciDataType.Raw:
|
|
case OciDataType.VarRaw:
|
|
case OciDataType.LongRaw:
|
|
case OciDataType.LongVarRaw:
|
|
return new OracleBinary ((byte[]) ovalue);
|
|
case OciDataType.Date:
|
|
case OciDataType.TimeStamp:
|
|
return new OracleDateTime ((DateTime) ovalue);
|
|
case OciDataType.Blob:
|
|
case OciDataType.Clob:
|
|
OracleLob lob = (OracleLob) ovalue;
|
|
return lob;
|
|
case OciDataType.Integer:
|
|
case OciDataType.Number:
|
|
case OciDataType.Float:
|
|
case OciDataType.VarNum:
|
|
case OciDataType.UnsignedInt:
|
|
return new OracleNumber ((decimal) ovalue);
|
|
case OciDataType.VarChar2:
|
|
case OciDataType.String:
|
|
case OciDataType.VarChar:
|
|
case OciDataType.Char:
|
|
case OciDataType.CharZ:
|
|
case OciDataType.OciString:
|
|
case OciDataType.LongVarChar:
|
|
case OciDataType.Long:
|
|
case OciDataType.RowIdDescriptor:
|
|
return new OracleString ((string) ovalue);
|
|
case OciDataType.IntervalDayToSecond:
|
|
return new OracleTimeSpan ((OracleTimeSpan) ovalue);
|
|
case OciDataType.IntervalYearToMonth:
|
|
return new OracleMonthSpan ((OracleMonthSpan) ovalue);
|
|
default:
|
|
// TODO: do other types
|
|
throw new NotImplementedException ();
|
|
}
|
|
}
|
|
|
|
[MonoTODO ("Be able to handle negative dates... i.e. BCE.")]
|
|
internal DateTime UnpackDate ()
|
|
{
|
|
byte century = Marshal.ReadByte (value, 0);
|
|
byte year = Marshal.ReadByte (value, 1);
|
|
byte month = Marshal.ReadByte (value, 2);
|
|
byte day = Marshal.ReadByte (value, 3);
|
|
byte hour = Marshal.ReadByte (value, 4);
|
|
byte minute = Marshal.ReadByte (value, 5);
|
|
byte second = Marshal.ReadByte (value, 6);
|
|
|
|
if (hour == 0)
|
|
hour ++;
|
|
if (minute == 0)
|
|
minute ++;
|
|
if (second == 0)
|
|
second ++;
|
|
|
|
return new DateTime ((century - 100) * 100 + (year - 100),
|
|
month,
|
|
day,
|
|
hour - 1,
|
|
minute - 1,
|
|
second - 1);
|
|
|
|
}
|
|
|
|
#endregion // Methods
|
|
}
|
|
}
|