I got a list of entries with a date, a text and a finished attribute.
I want to sort this list by the date. The date has the following format: dd.mm.yyyy
If I run this code, the result is mixed up like nothing happened. What's wrong?
this is my code:
// in the namespace
struct entry
{
public string date;
public string text;
public bool finished;
public entry(string _date, string _text, bool _finished)
{
date = _date;
text = _text;
finished = _finished;
}
}
// in my class
List<entry> entrys = new List<entry>();
// ** fill the list with content **
// where i want to sort the list
entrys.Sort(delegate (entry x, entry y)
{
string date1 = x.date;
string date2 = y.date;
// 0123456789
// dd.mm.yyyy
int day1 = Convert.ToInt32(date1.Substring(0, 2));
int day2 = Convert.ToInt32(date2.Substring(0, 2));
int month1 = Convert.ToInt32(date1.Substring(3, 2));
int month2 = Convert.ToInt32(date2.Substring(3, 2));
int year1 = Convert.ToInt32(date1.Substring(6, 4));
int year2 = Convert.ToInt32(date2.Substring(6, 4));
if (year1 > year2) return -1;
if (month1 > month2) return -1;
if (day1 > day2) return -1;
return 1;
});
You're really doing this the hard way:
var entries = new List<entry>();
// ** fill the list with content **
entries = entries.OrderBy(e => DateTime.ParseExact(e.date, "dd.MM.yyyy", null)).ToList();
And one wonders why you don't already have .date property as a DateTime type instead of a string.
Your date field should become a DateTime. However, if for some reason you need it to be a string, then do the following:
First, add a GetDate method to your entry structure:
public DateTime GetDate()
{
int day = Convert.ToInt32(date.Substring(0, 2));
int month = Convert.ToInt32(date.Substring(3, 2));
int year = Convert.ToInt32(date.Substring(6, 4));
return new DateTime(year,month,day);
}
Then, use the following when you sort:
entrys.Sort((x, y) => x.GetDate().CompareTo(y.GetDate()));
this code works:
entrys.Sort(delegate (entry x, entry y)
{
string date1 = x.date;
string date2 = y.date;
// 0123456789
// dd.mm.yyyy
int day1 = Convert.ToInt32(date1.Substring(0, 2));
int day2 = Convert.ToInt32(date2.Substring(0, 2));
int month1 = Convert.ToInt32(date1.Substring(3, 2));
int month2 = Convert.ToInt32(date2.Substring(3, 2));
int year1 = Convert.ToInt32(date1.Substring(6, 4));
int year2 = Convert.ToInt32(date2.Substring(6, 4));
if (year1 > year2) return 1;
if (year1 == year2 && month1 > month2) return 1;
if (year1 == year2 && month1 == month2 && day1 > day2) return 1;
return -1;
});
No need to manually parse strings if computer can do that for you:
var provider = System.Globalization.CultureInfo.InvariantCulture;
entrys.Sort((a, b) =>
DateTime.ParseExact(a.date, "dd.MM.yyyy", provider)
.CompareTo(DateTime.ParseExact(b.date, "dd.MM.yyyy", provider)));
Always follow the KISS (Keep It Simple Stupid) principle:
entrys.Sort(delegate (entry x, entry y)
{
DateTime dt1 = DateTime.ParseExact(x.date, "dd.MM.yyyy",
CultureInfo.InvariantCulture);
DateTime dt2 = DateTime.ParseExact(y.date, "dd.MM.yyyy",
CultureInfo.InvariantCulture);
return DateTime.Compare(dt1, dt2);
});
Just typed this quickly in LinqPad, the idea is to use Linq OrdeBy and defining a get property on the struct/class to return parsed DateTime. You can use TryPraseExact for additional safety.
void Main()
{
var list = new List<Entity>{
new Entity{TempDate = "25.10.2015", SomeData="data1"},
new Entity{TempDate = "20.10.2015", SomeData="data2"},
new Entity{TempDate = "26.10.2015", SomeData="data3"},
new Entity{TempDate = "18.10.2015", SomeData="data4"}};
list.Dump("Original");
list.OrderBy(x => x.DateTimeParsed).Dump("Sorted");
}
public struct Entity
{
public string TempDate {get; set;}
public DateTime DateTimeParsed{ get{ return DateTime.ParseExact(TempDate, "dd.mm.yyyy",CultureInfo.InvariantCulture); }}
public string SomeData {get; set;}
}
It is also a good idea to pass around DateTimeOffset instead of a string date
Related
Ok, so I have a date stored in UK format (dd/mm/yy) which I need to display in the locale of wherever the user might be.
The issue is that this date can be 000000 (00/00/2000); so I can't convert it to DateTime directly, as DateTime doesn't support 0 values for day or month.
I have this so far:
int dateInt = ddmmyy;
var year = (dateInt % 100) + 2000;
var month = (dateInt / 100) % 100;
var day = (dateInt / 100000);
var result = new DateTime(year, month, day); //2014/00/00 at this point, so breaks.
var resultStr = result.ToString(CultureInfo.InvariantCulture);
return resultStr;
What's the correct way to add support for 0 values initially? I've tried changing the 0 to 1 before converting to DateTime, running the conversion and then replacing with a 0 again; but due to culture variants I see no way that this method can support other cultures, which is the purpose of this conversion to begin with.
Any ideas? I'm guessing this is a common issue.
Is this what you need ?
using System;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
int[] savedDates = new int[] { 000000, 010000, 000013 };
foreach (var item in savedDates)
{
DateTime date = ConvertToDate(item);
Console.WriteLine(item.ToString("D6") + " => " + date.ToShortDateString());
}
Console.ReadLine();
}
private static DateTime ConvertToDate(int item)
{
string temp = item.ToString("D6");
int day = int.Parse(temp.Substring(0, 2));
int month = int.Parse(temp.Substring(2, 2));
int year = int.Parse(temp.Substring(4, 2));
if (day == 0)
day = 1;
if (month == 0)
month = 1;
year += 2000;
return new DateTime(year, month, day);
}
}
}
I would not store dates like this as the methodology for doing so is already provided by the .NET framework.
The best way to store dates would be to use Culture.InvariantCulture for string conversion cases and then convert to local culture for display purposes as necessary. DateTime itself is culture-independent so converting between cultures is very easy.
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
I am trying to convert Julian date string to DateTime but none of the solutions on the web seem to be working. I have a Julian date string 13324.
Julian Date: 13324
And I want to get the following DateTime
Date: 20-Nov-2013
Could you please direct me in the right direction. Thanks.
This is the simplest solution I can think of:
string julianDate = "13324";
int jDate = Convert.ToInt32(julianDate);
int day = jDate % 1000;
int year = (jDate - day) / 1000;
var date1 = new DateTime(year, 1, 1);
var result = date1.AddDays(day - 1);
(Note: this is all from memory; verify the syntax, etc.)
Sorry for my bad english
Try this code if the one on top didn't work. It worked for me.
public DateTime ConvertJulianToDatetime(string julianDate)
{
int dateint = int.Parse(julianDate);
DateTime dinicio = new DateTime(1840, 12, 31);
dinicio = dinicio.AddDays((double)dateint);
return dinicio;
}
This code is more reliable I think (can anyone notice):
public static DateTime FromJD(double JD)
{
return DateTime.FromOADate(JD - 2415018.5);
}
For MJD (modified julian day). Math.Floor or Math.Ceiling can be added as needed:
public static DateTime FromMJD(double MJD)
{
return DateTime.FromOADate((MJD - 2415018.5) + 2400000.5);
}
And one example for reverse translation:
public static double ToMJD(DateTime date)
{
return (date.ToOADate() + 2415018.5) -2400000.5;
}
public static double ToJD(DateTime date)
{
return date.ToOADate() + 2415018.5;
}
how do I used date on searching using Linq. I think I'm missing something on the declaration
string searchName = Request.Form["PersonName"];
DateTime searchDateFrom = Request.Form["ReceivedDateFrom"];
DateTime searchDateTo = Request.Form["ReceivedDateTo"];
var Results = (from va in _db.myTable
where ((va.PersonName.Contains(searchName)
&& (va.ApplicationReceivedDate > searchDateFrom
&& va.ApplicationReceivedDate < searchDateTo)
select va).ToList();
HttpRequest.Form is a NameValueCollection, where you can get strings in it by int/string indexer. That is, Request.Form["ReceivedDateFrom"] returns a string, you can't assign it to a variable whose type is DateTime without any convert. You can try DateTime.ParseExact method to convert the string to a DateTime. But if you can't guarantee the string has a correct format, you can use a TryParse method.
Might be a typo, but you need to cast searchDateFrom / searchDateTo to a DateTime and you have two extra open brackets in your linq statement
I'd also recommand using a cleaner indentation, it's easier to follow and count the brackets and stuff.
string searchName = Request.Form["PersonName"];
DateTime searchDateFrom = Request.Form["ReceivedDateFrom"];
DateTime searchDateTo = Request.Form["ReceivedDateTo"];
var Results = (from va in _db.myTable
where va.PersonName.Contains(searchName)
&& (va.ApplicationReceivedDate > searchDateFrom
&& va.ApplicationReceivedDate < searchDateTo)
select va).ToList();
This is when I setup a unit test to see what's going on.
Check your brackets and casting from string to datetime:
[TestMethod]
public void TestMethod1()
{
List<myTable> myTables = new List<myTable>();
for (int month = 1; month < 10; month++)
{
for (int day = 1; day < 20; day++)
{
myTables.Add(new myTable { PersonName = "Person " + month.ToString() + " " + day.ToString(), ApplicationReceivedDate = new DateTime(2011, month, day) });
}
}
string searchName = "Person";
DateTime searchDateFrom = Convert.ToDateTime("2011-01-02");
DateTime searchDateTo = Convert.ToDateTime("2011-01-03");
var Results = (from va in myTables
where va.PersonName.Contains(searchName)
&& va.ApplicationReceivedDate >= searchDateFrom
&& va.ApplicationReceivedDate < searchDateTo
select va);
Assert.AreEqual(Results.Count(), 1);
}
public class myTable
{
public string PersonName { get; set; }
public DateTime ApplicationReceivedDate { get; set; }
}
Also check the search from & to.
I have a date and I need to populate a drop-down with the months/years between that date and today. For instance, if that date is 10/14/2010 then the drop-down should contain October 2010, November 2010, December 2010, January 2011.
The way I'm thinking of doing this is to pass that date to a function, loop from today backwards step 1 month while adding each month to a collection until we reach that date and finally return a collection of strings. Then, populate the drop-down control on page load. Finally, use some ajax with a page method to parse back the string and trigger a partial page reload.
I'm just wondering if there's an easy way to do it.
Thanks.
Maybe you can try this:
static IEnumerable<DateTime> monthsBetween(DateTime startDate, DateTime endDate)
{
return Enumerable.Range(0, (endDate.Year - startDate.Year) * 12 + (endDate.Month - startDate.Month + 1))
.Select(m => new DateTime(startDate.Year, startDate.Month, 1).AddMonths(m));
}
This will not give you the result in the exact format that you want, but you get the drift. :)
You can do something like this which is pretty much what you described except counting forward:
private string[] FillDropDownWithDates(DateTime dt)
{
DateTime dtnow = DateTime.Now;
List<string> values = new List<string>();
if ( (dt <= dtnow))
{
values.Add(String.Format("{0:y}", dt));
}
while ( (dt = dt.AddMonths(1)) <= dtnow || ( dt.Month == dtnow.Month && dt.Year == dtnow.Year) )
{
values.Add(String.Format("{0:y}", dt)); // "March, 2008" YearMonth
}
return values.ToArray();
}
public static List<string> GetMonths(DateTime StartDate)
{
List<string> MonthList = new List<string>();
DateTime ThisMonth = DateTime.Now.Date;
while (ThisMonth.Date > StartDate.Date)
{
MonthList.Add(ThisMonth.ToString("MMMM") + " " + ThisMonth.Year.ToString());
ThisMonth = ThisMonth.AddMonths(-1);
}
return MonthList;
}
For Year,
public static IEnumerable<int> Range (int start, int count)
{
int end = start + count;
for (int i = start; i < end; i++)
yield return i;
}
var startYear = 2000;
YearDropDownList.ItemsSource= Enumerable.Range(startYear, 2050 - startYear + 1);
For Month,
An enumerable list with .ToString("MMMM") format.
This is how I got a 12 month/year. Hope the code helps.
public IEnumerable<SelectListItem> Additional12Months {
get
{
return Enumerable.Range(12, 12).Select(i => new SelectListItem { Value = DateTime.Now.AddMonths(-(i)).ToShortDateString(), Text = DateTime.Now.AddMonths(-(i)).ToString("MMM-yyyy") }).ToList();
}
}