How can the method be implemented in C#?
string StartTime = "06:10 PM";
string Endtime = "08:10 PM";
DateTime current_time = DateTime.Now;
bool validTime = validTimeFindout(StartTime,Endtime,current_time);
bool validTimeFindout(string StartTime, string Endtime,DateTime current_time){
// This method should return true
// when the current_time>= StartTime && current_time<=Endtime
// otherwise false
}
I tried to find out the valid time in the specific range and for that validTimeFindout method will help and here the method is comparing the time get from local pc and compare them with StartTime and Endtime
Starting with .NET 6, you can use the TimeOnly Struct:
static bool IsTimeBetween(string startTime, string endTime, DateTime dateTime)
{
if (TimeOnly.TryParse(startTime, out var t1) &&
TimeOnly.TryParse(endTime, out var t2))
{
return TimeOnly.FromDateTime(dateTime).IsBetween(t1, t2);
}
return false;
}
Note that TimeOnly.IsBetween supports time ranges that span midnight such as 23:00-01:00.
You can use DateTime.TryParse() method to parse a string into the DateTime datatype.
DateTime datatypes can be compared as numeric datatypes with <, <=, ==, !=, >=, >
bool validTimeFindout(string StartTime, string Endtime, DateTime current_time){
DateTime start;
DateTime.TryParse(StartTime, out start);
DateTime end;
DateTime.TryParse(Endtime, out end);
return current_time >= start && current_time <= end;
}
You just need to convert the inputs from string to datetime and do the calculations: datetime.parse()
bool validTimeFindout(string StartTime, string Endtime, DateTime current_time)
{
DateTime _startTime = DateTime.Parse(StartTime);
DateTime _endTime = DateTime.Parse(Endtime);
if (current_time >= _startTime && current_time <= _endTime)
return true;
else
return false;
}
First you need to convert those strings to DateTime objects.
Then you should compare those DateTime objects and current time.
using System.Globalization;
string StartTime = "06:10 PM";
string Endtime = "08:10 PM";
DateTime current_time = DateTime.Now;
try {
bool validTime = validTimeFindout(StartTime, Endtime, current_time);
Console.WriteLine(validTime);
}catch(Exception exc) {
Console.WriteLine(exc.Message);
}
bool validTimeFindout(string StartTime, string Endtime, DateTime current_time) {
DateTime start = ParseTimeString(StartTime);
DateTime end = ParseTimeString(Endtime);
if(current_time.CompareTo(start) >= 0 && current_time.CompareTo(end) <= 0) {
return true;
} else {
return false;
}
}
DateTime ParseTimeString(string timeString) {
string format = "hh:mm tt";
DateTime result;
if (DateTime.TryParseExact(timeString, format, CultureInfo.GetCultureInfo("en-US"), DateTimeStyles.None, out result)) {
return result;
} else {
throw new Exception("Cannot parse time!");
}
}
There are also several things you can rethink and fix.
Naming pattern - IMHO is valid is not a good name for method checking if a DateTime is between other DateTimes.
Use single naming convention and stick to it. The most popular convention in C# is cammel case (like startTime).
Is it really needed to store those DateTimes in strings formatted like "01:10 PM"? Why doesn't you simply store DateTime objects?
How do I find the start of the week (both Sunday and Monday) knowing just the current time in C#?
Something like:
DateTime.Now.StartWeek(Monday);
Use an extension method:
public static class DateTimeExtensions
{
public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek)
{
int diff = (7 + (dt.DayOfWeek - startOfWeek)) % 7;
return dt.AddDays(-1 * diff).Date;
}
}
Which can be used as follows:
DateTime dt = DateTime.Now.StartOfWeek(DayOfWeek.Monday);
DateTime dt = DateTime.Now.StartOfWeek(DayOfWeek.Sunday);
The quickest way I can come up with is:
var sunday = DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek);
If you would like any other day of the week to be your start date, all you need to do is add the DayOfWeek value to the end
var monday = DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek + (int)DayOfWeek.Monday);
var tuesday = DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek + (int)DayOfWeek.Tuesday);
A little more verbose and culture-aware:
System.Globalization.CultureInfo ci =
System.Threading.Thread.CurrentThread.CurrentCulture;
DayOfWeek fdow = ci.DateTimeFormat.FirstDayOfWeek;
DayOfWeek today = DateTime.Now.DayOfWeek;
DateTime sow = DateTime.Now.AddDays(-(today - fdow)).Date;
Using Fluent DateTime:
var monday = DateTime.Now.Previous(DayOfWeek.Monday);
var sunday = DateTime.Now.Previous(DayOfWeek.Sunday);
Ugly but it at least gives the right dates back
With start of week set by system:
public static DateTime FirstDateInWeek(this DateTime dt)
{
while (dt.DayOfWeek != System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat.FirstDayOfWeek)
dt = dt.AddDays(-1);
return dt;
}
Without:
public static DateTime FirstDateInWeek(this DateTime dt, DayOfWeek weekStartDay)
{
while (dt.DayOfWeek != weekStartDay)
dt = dt.AddDays(-1);
return dt;
}
Let's combine the culture-safe answer and the extension method answer:
public static class DateTimeExtensions
{
public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek)
{
System.Globalization.CultureInfo ci = System.Threading.Thread.CurrentThread.CurrentCulture;
DayOfWeek fdow = ci.DateTimeFormat.FirstDayOfWeek;
return DateTime.Today.AddDays(-(DateTime.Today.DayOfWeek- fdow));
}
}
This would give you the preceding Sunday (I think):
DateTime t = DateTime.Now;
t -= new TimeSpan ((int) t.DayOfWeek, 0, 0, 0);
For Monday
DateTime startAtMonday = DateTime.Now.AddDays(DayOfWeek.Monday - DateTime.Now.DayOfWeek);
For Sunday
DateTime startAtSunday = DateTime.Now.AddDays(DayOfWeek.Sunday- DateTime.Now.DayOfWeek);
This may be a bit of a hack, but you can cast the .DayOfWeek property to an int (it's an enum and since its not had its underlying data type changed it defaults to int) and use that to determine the previous start of the week.
It appears the week specified in the DayOfWeek enum starts on Sunday, so if we subtract 1 from this value that'll be equal to how many days the Monday is before the current date. We also need to map the Sunday (0) to equal 7 so given 1 - 7 = -6 the Sunday will map to the previous Monday:-
DateTime now = DateTime.Now;
int dayOfWeek = (int)now.DayOfWeek;
dayOfWeek = dayOfWeek == 0 ? 7 : dayOfWeek;
DateTime startOfWeek = now.AddDays(1 - (int)now.DayOfWeek);
The code for the previous Sunday is simpler as we don't have to make this adjustment:-
DateTime now = DateTime.Now;
int dayOfWeek = (int)now.DayOfWeek;
DateTime startOfWeek = now.AddDays(-(int)now.DayOfWeek);
using System;
using System.Globalization;
namespace MySpace
{
public static class DateTimeExtention
{
// ToDo: Need to provide culturaly neutral versions.
public static DateTime GetStartOfWeek(this DateTime dt)
{
DateTime ndt = dt.Subtract(TimeSpan.FromDays((int)dt.DayOfWeek));
return new DateTime(ndt.Year, ndt.Month, ndt.Day, 0, 0, 0, 0);
}
public static DateTime GetEndOfWeek(this DateTime dt)
{
DateTime ndt = dt.GetStartOfWeek().AddDays(6);
return new DateTime(ndt.Year, ndt.Month, ndt.Day, 23, 59, 59, 999);
}
public static DateTime GetStartOfWeek(this DateTime dt, int year, int week)
{
DateTime dayInWeek = new DateTime(year, 1, 1).AddDays((week - 1) * 7);
return dayInWeek.GetStartOfWeek();
}
public static DateTime GetEndOfWeek(this DateTime dt, int year, int week)
{
DateTime dayInWeek = new DateTime(year, 1, 1).AddDays((week - 1) * 7);
return dayInWeek.GetEndOfWeek();
}
}
}
Putting it all together, with Globalization and allowing for specifying the first day of the week as part of the call we have
public static DateTime StartOfWeek ( this DateTime dt, DayOfWeek? firstDayOfWeek )
{
DayOfWeek fdow;
if ( firstDayOfWeek.HasValue )
{
fdow = firstDayOfWeek.Value;
}
else
{
System.Globalization.CultureInfo ci = System.Threading.Thread.CurrentThread.CurrentCulture;
fdow = ci.DateTimeFormat.FirstDayOfWeek;
}
int diff = dt.DayOfWeek - fdow;
if ( diff < 0 )
{
diff += 7;
}
return dt.AddDays( -1 * diff ).Date;
}
Step 1:
Create a static class
public static class TIMEE
{
public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek)
{
int diff = (7 + (dt.DayOfWeek - startOfWeek)) % 7;
return dt.AddDays(-1 * diff).Date;
}
public static DateTime EndOfWeek(this DateTime dt, DayOfWeek startOfWeek)
{
int diff = (7 - (dt.DayOfWeek - startOfWeek)) % 7;
return dt.AddDays(1 * diff).Date;
}
}
Step 2: Use this class to get both start and end day of the week
DateTime dt = TIMEE.StartOfWeek(DateTime.Now ,DayOfWeek.Monday);
DateTime dt1 = TIMEE.EndOfWeek(DateTime.Now, DayOfWeek.Sunday);
var now = System.DateTime.Now;
var result = now.AddDays(-((now.DayOfWeek - System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat.FirstDayOfWeek + 7) % 7)).Date;
This would give you midnight on the first Sunday of the week:
DateTime t = DateTime.Now;
t -= new TimeSpan ((int) t.DayOfWeek, t.Hour, t.Minute, t.Second);
This gives you the first Monday at midnight:
DateTime t = DateTime.Now;
t -= new TimeSpan ((int) t.DayOfWeek - 1, t.Hour, t.Minute, t.Second);
Try with this in C#. With this code you can get both the first date and last date of a given week. Here Sunday is the first day and Saturday is the last day, but you can set both days according to your culture.
DateTime firstDate = GetFirstDateOfWeek(DateTime.Parse("05/09/2012").Date, DayOfWeek.Sunday);
DateTime lastDate = GetLastDateOfWeek(DateTime.Parse("05/09/2012").Date, DayOfWeek.Saturday);
public static DateTime GetFirstDateOfWeek(DateTime dayInWeek, DayOfWeek firstDay)
{
DateTime firstDayInWeek = dayInWeek.Date;
while (firstDayInWeek.DayOfWeek != firstDay)
firstDayInWeek = firstDayInWeek.AddDays(-1);
return firstDayInWeek;
}
public static DateTime GetLastDateOfWeek(DateTime dayInWeek, DayOfWeek firstDay)
{
DateTime lastDayInWeek = dayInWeek.Date;
while (lastDayInWeek.DayOfWeek != firstDay)
lastDayInWeek = lastDayInWeek.AddDays(1);
return lastDayInWeek;
}
I tried several, but I did not solve the issue with a week starting on a Monday, resulting in giving me the coming Monday on a Sunday. So I modified it a bit and got it working with this code:
int delta = DayOfWeek.Monday - DateTime.Now.DayOfWeek;
DateTime monday = DateTime.Now.AddDays(delta == 1 ? -6 : delta);
return monday;
The same for end of the week (in style of Compile This's answer):
public static DateTime EndOfWeek(this DateTime dt)
{
int diff = 7 - (int)dt.DayOfWeek;
diff = diff == 7 ? 0 : diff;
DateTime eow = dt.AddDays(diff).Date;
return new DateTime(eow.Year, eow.Month, eow.Day, 23, 59, 59, 999) { };
}
Thanks for the examples. I needed to always use the "CurrentCulture" first day of the week and for an array I needed to know the exact Daynumber.. so here are my first extensions:
public static class DateTimeExtensions
{
//http://stackoverflow.com/questions/38039/how-can-i-get-the-datetime-for-the-start-of-the-week
//http://stackoverflow.com/questions/1788508/calculate-date-with-monday-as-dayofweek1
public static DateTime StartOfWeek(this DateTime dt)
{
//difference in days
int diff = (int)dt.DayOfWeek - (int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek; //sunday=always0, monday=always1, etc.
//As a result we need to have day 0,1,2,3,4,5,6
if (diff < 0)
{
diff += 7;
}
return dt.AddDays(-1 * diff).Date;
}
public static int DayNoOfWeek(this DateTime dt)
{
//difference in days
int diff = (int)dt.DayOfWeek - (int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek; //sunday=always0, monday=always1, etc.
//As a result we need to have day 0,1,2,3,4,5,6
if (diff < 0)
{
diff += 7;
}
return diff + 1; //Make it 1..7
}
}
Here is a correct solution. The following code works regardless if the first day of the week is a Monday or a Sunday or something else.
public static class DateTimeExtension
{
public static DateTime GetFirstDayOfThisWeek(this DateTime d)
{
CultureInfo ci = System.Threading.Thread.CurrentThread.CurrentCulture;
var first = (int)ci.DateTimeFormat.FirstDayOfWeek;
var current = (int)d.DayOfWeek;
var result = first <= current ?
d.AddDays(-1 * (current - first)) :
d.AddDays(first - current - 7);
return result;
}
}
class Program
{
static void Main()
{
System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en-US");
Console.WriteLine("Current culture set to en-US");
RunTests();
Console.WriteLine();
System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("da-DK");
Console.WriteLine("Current culture set to da-DK");
RunTests();
Console.ReadLine();
}
static void RunTests()
{
Console.WriteLine("Today {1}: {0}", DateTime.Today.Date.GetFirstDayOfThisWeek(), DateTime.Today.Date.ToString("yyyy-MM-dd"));
Console.WriteLine("Saturday 2013-03-02: {0}", new DateTime(2013, 3, 2).GetFirstDayOfThisWeek());
Console.WriteLine("Sunday 2013-03-03: {0}", new DateTime(2013, 3, 3).GetFirstDayOfThisWeek());
Console.WriteLine("Monday 2013-03-04: {0}", new DateTime(2013, 3, 4).GetFirstDayOfThisWeek());
}
}
Modulo in C# works bad for -1 mod 7 (it should be 6, but C# returns -1)
so... a "one-liner" solution to this will look like this :)
private static DateTime GetFirstDayOfWeek(DateTime date)
{
return date.AddDays(
-(((int)date.DayOfWeek - 1) -
(int)Math.Floor((double)((int)date.DayOfWeek - 1) / 7) * 7));
}
I did it for Monday, but with similar logic for Sunday.
public static DateTime GetStartOfWeekDate()
{
// Get today's date
DateTime today = DateTime.Today;
// Get the value for today. DayOfWeek is an enum with 0 being Sunday, 1 Monday, etc
var todayDayOfWeek = (int)today.DayOfWeek;
var dateStartOfWeek = today;
// If today is not Monday, then get the date for Monday
if (todayDayOfWeek != 1)
{
// How many days to get back to Monday from today
var daysToStartOfWeek = (todayDayOfWeek - 1);
// Subtract from today's date the number of days to get to Monday
dateStartOfWeek = today.AddDays(-daysToStartOfWeek);
}
return dateStartOfWeek;
}
The following method should return the DateTime that you want. Pass in true for Sunday being the first day of the week, false for Monday:
private DateTime getStartOfWeek(bool useSunday)
{
DateTime now = DateTime.Now;
int dayOfWeek = (int)now.DayOfWeek;
if(!useSunday)
dayOfWeek--;
if(dayOfWeek < 0)
{// day of week is Sunday and we want to use Monday as the start of the week
// Sunday is now the seventh day of the week
dayOfWeek = 6;
}
return now.AddDays(-1 * (double)dayOfWeek);
}
You could use the excellent Umbrella library:
using nVentive.Umbrella.Extensions.Calendar;
DateTime beginning = DateTime.Now.BeginningOfWeek();
However, they do seem to have stored Monday as the first day of the week (see the property nVentive.Umbrella.Extensions.Calendar.DefaultDateTimeCalendarExtensions.WeekBeginsOn), so that previous localized solution is a bit better. Unfortunate.
Edit: looking closer at the question, it looks like Umbrella might actually work for that too:
// Or DateTime.Now.PreviousDay(DayOfWeek.Monday)
DateTime monday = DateTime.Now.PreviousMonday();
DateTime sunday = DateTime.Now.PreviousSunday();
Although it's worth noting that if you ask for the previous Monday on a Monday, it'll give you seven days back. But this is also true if you use BeginningOfWeek, which seems like a bug :(.
Following on from Compile This' answer, use the following method to obtain the date for any day of the week:
public static DateTime GetDayOfWeek(DateTime dateTime, DayOfWeek dayOfWeek)
{
var monday = dateTime.Date.AddDays((7 + (dateTime.DayOfWeek - DayOfWeek.Monday) % 7) * -1);
var diff = dayOfWeek - DayOfWeek.Monday;
if (diff == -1)
{
diff = 6;
}
return monday.AddDays(diff);
}
This will return both the beginning of the week and the end of the week dates:
private string[] GetWeekRange(DateTime dateToCheck)
{
string[] result = new string[2];
TimeSpan duration = new TimeSpan(0, 0, 0, 0); //One day
DateTime dateRangeBegin = dateToCheck;
DateTime dateRangeEnd = DateTime.Today.Add(duration);
dateRangeBegin = dateToCheck.AddDays(-(int)dateToCheck.DayOfWeek);
dateRangeEnd = dateToCheck.AddDays(6 - (int)dateToCheck.DayOfWeek);
result[0] = dateRangeBegin.Date.ToString();
result[1] = dateRangeEnd.Date.ToString();
return result;
}
I have posted the complete code for calculating the begin/end of week, month, quarter and year on my blog
ZamirsBlog
Calculating this way lets you choose which day of the week indicates the start of a new week (in the example I chose Monday).
Note that doing this calculation for a day that is a Monday will give the current Monday and not the previous one.
//Replace with whatever input date you want
DateTime inputDate = DateTime.Now;
//For this example, weeks start on Monday
int startOfWeek = (int)DayOfWeek.Monday;
//Calculate the number of days it has been since the start of the week
int daysSinceStartOfWeek = ((int)inputDate.DayOfWeek + 7 - startOfWeek) % 7;
DateTime previousStartOfWeek = inputDate.AddDays(-daysSinceStartOfWeek);
I work with a lot of schools, so correctly using Monday as the first day of the week is important here.
A lot of the most terse answers here don't work on Sunday -- we often end up returning the date of tomorrow on Sunday, which is not good for running a report on last week's activities.
Here's my solution, which returns last Monday on Sunday, and today on Monday.
// Adding 7 so remainder is always positive; Otherwise % returns -1 on Sunday.
var daysToSubtract = (7 + (int)today.DayOfWeek - (int)DayOfWeek.Monday) % 7;
var monday = today
.AddDays(-daysToSubtract)
.Date;
Remember to use a method parameter for "today" so it's unit testable!!
Here is a combination of a few of the answers. It uses an extension method that allows the culture to be passed in. If one is not passed in, the current culture is used. This will give it maximum flexibility and reuse.
/// <summary>
/// Gets the date of the first day of the week for the date.
/// </summary>
/// <param name="date">The date to be used</param>
/// <param name="cultureInfo">If none is provided, the current culture is used</param>
/// <returns>The date of the beggining of the week based on the culture specifed</returns>
public static DateTime StartOfWeek(this DateTime date, CultureInfo cultureInfo=null) =>
date.AddDays(-1 * (7 + (date.DayOfWeek - (cultureInfo ?? CultureInfo.CurrentCulture).DateTimeFormat.FirstDayOfWeek)) % 7).Date;
Example Usage:
public static void TestFirstDayOfWeekExtension() {
DateTime date = DateTime.Now;
foreach(System.Globalization.CultureInfo culture in CultureInfo.GetCultures(CultureTypes.UserCustomCulture | CultureTypes.SpecificCultures)) {
Console.WriteLine($"{culture.EnglishName}: {date.ToShortDateString()} First Day of week: {date.StartOfWeek(culture).ToShortDateString()}");
}
}
If you want Saturday or Sunday or any day of week, but not exceeding the current week (Sat-Sun), I got you covered with this piece of code.
public static DateTime GetDateInCurrentWeek(this DateTime date, DayOfWeek day)
{
var temp = date;
var limit = (int)date.DayOfWeek;
var returnDate = DateTime.MinValue;
if (date.DayOfWeek == day)
return date;
for (int i = limit; i < 6; i++)
{
temp = temp.AddDays(1);
if (day == temp.DayOfWeek)
{
returnDate = temp;
break;
}
}
if (returnDate == DateTime.MinValue)
{
for (int i = limit; i > -1; i++)
{
date = date.AddDays(-1);
if (day == date.DayOfWeek)
{
returnDate = date;
break;
}
}
}
return returnDate;
}
We like one-liners: Get the difference between the current culture's first day of week and the current day, and then subtract the number of days from the current day:
var weekStartDate = DateTime.Now.AddDays(-((int)now.DayOfWeek - (int)DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek));
There is a string 2020-12-27 20:00:00. An application must parse it to DateTime structure. Expected format is yyyy-MM-dd hh:mm:ss.
I use:
DateTime.TryParseExact(timeString, "yyyy-MM-dd hh:mm:ss",
CultureInfo.InvariantCulture, DateTimeStyles.None, out time)
but it doesn't work. TryParseExact returns false.
Anyone knows why?
You need to use HH instead of hh specifier.
HH specifier is for 24-hour clock format (00 to 23) but hh specifier is for 12-hour clock format (01 to 12).
string s = "2020-12-27 20:00:00";
DateTime dt;
if(DateTime.TryParseExact(s, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture,
DateTimeStyles.None, out dt))
{
// 27.12.2020 20:00:00
}
hh is 12 hours format, you should use HH for 24 hours
So your example becomes:
DateTime.TryParseExact(timeString, "yyyy-MM-dd HH:mm:ss",
CultureInfo.InvariantCulture, DateTimeStyles.None, out time)
You can use method I wrote for purpose of converting DTs from string of any format:
public static DateTime? parseDate(this string date, string format = #"ddMMyyyy")
{
format += "HHmmss";
DateTime dt;
try
{
string day = date.Substring(format.IndexOf('d'), 2);
string month = date.Substring(format.IndexOf('M'), 2);
string year = date.Substring(format.IndexOf('y'), 4);
string hour = date.Length - 1 > format.IndexOf('H')? date.Substring(format.IndexOf('H'), 2) : "00";
string minute = date.Length - 1 > format.IndexOf('m')? date.Substring(format.IndexOf('m'), 2) : "00";
string second = date.Length - 1 > format.IndexOf('s')? date.Substring(format.IndexOf('s'), 2) : "00";
dt = DateTime.Parse(year + "/" + month + "/" + day + " " + hour + ":" + minute + ":" + second);
}
catch { return null; }
return dt;
}
Usage:
string date = "2014ASDA04QWER05zxc";
DateTime? dt = date.parseDate("yyyyxxxxMMxxxxdd");
Result: 2014/04/05 00:00
However you are right maybe you should just use DateTime.ParseExact with HH instead of hh as my method is overcomplicated for this.
Little comparison of two methods using 20 000 random dates:
I have timestamp of Oracle:
string timestamp = "23-JUN-14 09.39.04.000000000 AM";
I am not able to parse it into system date time object. I used:
CultureInfo provider = CultureInfo.InvariantCulture;
String format = "yy-MMM-dd hh:mm:ss:fffffff";
string timestamp = "10-DEC-07 10.32.47.797201123 AM";
{
var date = DateTime.ParseExact(timestamp, format, provider);
DateTime dateTime = DateTime.ParseExact(timestamp.ToString(), "dd-MMM-y HH:mm:ss", CultureInfo.InvariantCulture);
}
It is still passing error. It is working 7 f after m but not more than that. I used try Parse, try ParseExact - is there any way?
According to https://stackoverflow.com/a/23198962/328864, there is no way to skip parts of an exact pattern, so i guess you could do something like this:
CultureInfo provider = CultureInfo.InvariantCulture;
string timestamp = "10-DEC-07 10.32.47.797201123 AM";
String format = String.Format("yy-MMM-dd hh.mm.ss.fffffff{0} tt", timestamp.Substring(26,2));
DateTime date = DateTime.ParseExact(timestamp, format, provider);
Console.WriteLine(date);
Not very pretty though.
Once we started to use ODP.NET, we had to implement an extension like below:
public static T ConvertOracleValue<T>(this object value)
{
if (value != null)
{
Type typeOfValue = value.GetType();
if (typeOfValue.Namespace.Contains("Oracle.DataAccess"))
{
if (typeOfValue.Name.Equals("OracleTimeStamp"))
{
int tempInt = 0;
Oracle.DataAccess.Types.OracleTimeStamp ots = (Oracle.DataAccess.Types.OracleTimeStamp)value;
tempInt = Int32.TryParse(ots.Millisecond.ToString("000").Substring(0, 3), out tempInt) ? tempInt : 0;
DateTime ret = new DateTime(ots.Year, ots.Month, ots.Day, ots.Hour, ots.Minute, ots.Second, tempInt);
return ConvertHelper.ConvertValue<T>(ret);
}
if (typeOfValue.Name.Equals("OracleTimeStampLTZ"))
{
int tempInt = 0;
Oracle.DataAccess.Types.OracleTimeStampLTZ ots = (Oracle.DataAccess.Types.OracleTimeStampLTZ)value;
tempInt = Int32.TryParse(ots.Millisecond.ToString("000").Substring(0, 3), out tempInt) ? tempInt : 0;
DateTime ret = new DateTime(ots.Year, ots.Month, ots.Day, ots.Hour, ots.Minute, ots.Second, tempInt);
return ConvertHelper.ConvertValue<T>(ret);
}
if (typeOfValue.Name.Equals("OracleTimeStampTZ"))
{
int tempInt = 0;
Oracle.DataAccess.Types.OracleTimeStampTZ ots = (Oracle.DataAccess.Types.OracleTimeStampTZ)value;
tempInt = Int32.TryParse(ots.Millisecond.ToString("000").Substring(0, 3), out tempInt) ? tempInt : 0;
DateTime ret = new DateTime(ots.Year, ots.Month, ots.Day, ots.Hour, ots.Minute, ots.Second, tempInt);
return ConvertHelper.ConvertValue<T>(ret);
}
string temp = value.ToString();
return ConvertHelper.ConvertValue<T>(temp);
}
}
else
{
return default(T);
}
return ConvertHelper.ConvertValue<T>(value);
}
where ConvertHelper.ConvertValue is another extension:
public static class ConvertHelper
{
public static T ConvertValue<T>(object value)
{
Type typeOfT = typeof(T);
if (typeOfT.BaseType != null && typeOfT.BaseType.ToString() == "System.Enum")
{
return (T)Enum.Parse(typeOfT, Convert.ToString(value));
}
if ((value == null || value == Convert.DBNull) && (typeOfT.IsValueType))
{
return default(T);
}
if (value is IConvertible)
{
return (T)Convert.ChangeType(value, typeOfT, new CultureInfo("en-GB"));
}
return (T)Convert.ChangeType(value, typeOfT);
}
}
This worked like a charm in our test, integration and production environments.
.NET DateTime structure has a precision of tick - 100 nanoseconds - 0.0000001 of second - 7 decimal positions after the point.
Oracle TimeStamp has a precision of up to nanosecond - 0.000000001 - 9 decimal positions after the point.
That is why standard DateTime cannot store all possible oracle TimeStamps. And its parsing function simply fail on more precise string representations of TimeStamp.
So, what could be tried:
Format your TimeStamps in query to some format parseable by DataTime(with loss of precision if necessary) - http://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements004.htm
Or create your own more precise CustomTimeStamp .Net structure and parse to it manually