Formatting DateTime string inside of a linq statement - c#

I have a web api set up where I'm displaying information on my site via entity framework. I'm filtering my data so it only pulls back the specific parts I want, which includes a DateTime value.
[HttpGet]
public IEnumerable<Log> XmlLog()
{
var userLog = _db.Logs.Where(x => x.EngineType == "Xml");
return userLog .ToList();
}
This displays my date as:
2019-02-05T15:11:50.39
What I need to do is change the DateTime format to be something else. Ideally:
Saturday 2 February 9:12:30
On my linq call I've tried the following:
[HttpGet]
public IEnumerable<Log> XmlLog()
{
var userLog = _db.Logs.Select(d => d.LogDate.ToString("f")).Where(x => x.EngineType == "Xml");
return userLog .ToList();
}
And on my model itself I have tried the following attributes:
[DataType(DataType.DateTime)]
[DisplayFormat(DataFormatString = "{0:yyyy/MM/dd HH:mm:ss}")]
public DateTime LogDate { get; set; }
Neither of my attempts has worked. What is it I'm doing wrong in my statements?
The above is written in DotNet 4.7 and not in DotNetCore.

As John has commented, your LINQ should be throwing an exception, because you first select strings, and then try to filter them as though they are objects.
But this approach is backwards anyway. This is just about getting the data, so it should just stay as it is, without any formatting. Let your view layer be responsible for formatting.
The DisplayFormat attribute is great, but only if you are using Html.DisplayFor/Html.EditorFor helpers. If you are doing just something like #Model.LogDate in your view, consider calling ToString(format) with the format you need.
Finally, your format does not look like example you wish it was. The correct format you are looking for is: dddd, dd MMMM HH:mm:ss.
All in all, leave the filter as it is, and either use DisplayFor with this annotation:
[DataType(DataType.DateTime)]
[DisplayFormat(DataFormatString = "{0:dddd, dd MMMM HH:mm:ss}")]
public DateTime LogDate { get; set; }
...
#Html.DisplayFor(m => m[i].LogDate)
Or don't bother with any annotations, and just use
#Model[i].LogDate.ToString("dddd, dd MMMM HH:mm:ss")

Related

How to get DateTime From Database in Solar Date Fromat (Shamsi Date)?

I am trying to get DataTime from database in Persian Date Fromat,
For this task i made an extinsion method,
and my App Culture is FA-fa, So the DateTime.Now returning Persian Date.
Here is cultureInfo
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("fa-AF");
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("fa-AF");
Here is My Code in ViewModel Which makes error:
long mntRevenue = (long)db.StudentFees
.Where(f => DateConverter.ToPersianDate(f.Date).Month == DateTime.Now.Month).Sum(s => s.Pay);
Error is:
System.InvalidOperationException: 'The LINQ expression 'DbSet()
.Where(s => (DateTime?)s.Date
.ToPersianDate().Month == DateTime.Now.Month)' could not be translated. Additional information: Translation of method 'SchoolViewModel.ViewModels.DateConverter.ToPersianDate' failed. If this method can be mapped to your custom function, see https://go.microsoft.com/fwlink/?linkid=2132413 for more information.
Translation of method 'SchoolViewModel.ViewModels.DateConverter.ToPersianDate' failed. If this method can be mapped to your custom function, see https://go.microsoft.com/fwlink/?linkid=2132413 for more information. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.'
My Extinsion Method is:
public static class DateConverter
{
#region Static Methods
public static DateTime ToPersianDate(this DateTime? dt)
{
try
{
DateTime dateTime = dt ?? DateTime.Now;
PersianCalendar persianCalendar = new PersianCalendar();
string year = persianCalendar.GetYear(dateTime).ToString();
string month = persianCalendar.GetMonth(dateTime).ToString()
.PadLeft(2, '0');
string day = persianCalendar.GetDayOfMonth(dateTime).ToString()
.PadLeft(2, '0');
string hour = dateTime.Hour.ToString().PadLeft(2, '0');
string minute = dateTime.Minute.ToString().PadLeft(2, '0');
string second = dateTime.Second.ToString().PadLeft(2, '0');
return DateTime.Parse(String.Format("{0}/{1}/{2} {3}:{4}:{5}", year, month, day, hour, minute, second));
}
catch { return DateTime.Now; }
}
#endregion
}
I want to get date from database and compare it with Current Month and give the compare result to linq expression. The DateTime should be in the Persian Format (Shamsi Date).
Thanks for all who leaves comments, Specially #lets do it.
I found the solution,
I just Remove the ToPersianDate Extinsion Method and Add DateAndPay class,
DateAndPay Class:
public class DateAndPay
{
public DateTime Date { get; set; }
public int Pay { get; set; }
}
Here it is:
PersianCalendar persianCalendar = new PersianCalendar();
int month = persianCalendar.GetMonth(DateTime.Now);
using AppDbContext db = new();
List<DateAndPay> studentFee = await db.StudentFees.Select(f => new DateAndPay { Date= f.Date,Pay= f.Pay }).ToListAsync();
long mntRevenue = (long)studentFee.Where(f => persianCalendar.GetMonth(f.Date) == month).Sum(f=> f.Pay);

DateTimeOffset: TZ Offset is reset to +00:00 when fetching data from LiteDb collection

When inserting, the offset is OK, however when retrieving the document, it's resetting to +00:00
Property:
public DateTimeOffset CreatedOn { get; set; }
Insert:
user.CreatedOn = DateTimeOffset.Now; // 01/20/2021 6:05:21 PM +05:30
col.Insert(user);
col.EnsureIndex(x => x.Username);
Find:
using (var db = _liteDbConnection.Create() as LiteDatabase)
{
var col = db.GetCollection<AuthUser>(USERS_COLLECTION);
return col.FindOne(x => x.UserId == userId);
}
user.CreatedOn becomes
01/20/2021 6:05:21 PM +00:00
Am I doing something wrong?
From the documentation
Following the BSON specification, DateTime values are stored only up to the miliseconds. All DateTime values are converted to UTC on storage and converted back to local time on retrieval.
It doesn't look like there's actual DateTimeOffset support. (Personally I think it's a terrible idea to convert to local time on retrieval, but that's a slightly different matter.) Additionally, it looks like it's not really converting to local time properly, given the incorrect offset of 0.
I would suggest avoiding using DateTimeOffset with LiteDb until it's really supported (maintaining the offset).
This happens because LiteDB stores a DateTimeOffset using value.UtcDateTime. This is unfortunate, but it can't be changed due to compatibility. However, you can override this behavior by creating a custom serializer:
BsonMapper.Global.RegisterType<DateTimeOffset>
(
serialize: obj =>
{
var doc = new BsonDocument();
doc["DateTime"] = obj.DateTime.Ticks;
doc["Offset"] = obj.Offset.Ticks;
return doc;
},
deserialize: doc => new DateTimeOffset(doc["DateTime"].AsInt64, new TimeSpan(doc["Offset"].AsInt64))
);

Search works on all fields except the date field

I'd like to search data by date with format (dd/MM/yyyy) for example "20/01/2021". the search works on ADDRESS and NAME fields but not on the CREATE_DATE.
This is my code :
// search
if (!string.IsNullOrEmpty(search))
{
List<string> terms = search.Split(',').ToList().ConvertAll(d => d.ToLower());
res = res.Where(x =>
terms.Any(
str => x.NAME.Contains(str) ||
x.ADDRESS.Contains(str) ||
x.DATE_CREATE.ToString().Contains(str)
));
var test = res.FirstOrDefault().DATE_CREATE.ToString();
}
This is the request :
http://localhost:6289/api/Customer?search=20/01/2021,hous
and this is the outputs of terms and test var :
and this is how the dates are saved , they dates are with datetime type
Your code actually works on my machine BUT only in case I use appropriate culture settings as #JustShadow pointed out.
Appropriate culture: which results a datetime.ToString() formating date in dd/MM/yyyy format.
For test purpose I used "es-ES" culture for example with the following code inside your if statement:
Thread.CurrentThread.CurrentCulture = new CultureInfo("es-ES");
I suggest modifying your code according to this:
if (!string.IsNullOrEmpty(search))
{
List<string> terms = search.Split(',').ToList().ConvertAll(d => d.ToLower());
var originalCulture = Thread.CurrentThread.CurrentCulture;
try
{
// use any locale which results a datetime.ToString() output in dd/MM/yyyy format
Thread.CurrentThread.CurrentCulture = new CultureInfo("es-ES"); ;
res = res.Where(x =>
terms.Any(
str => x.NAME.Contains(str) ||
x.ADDRESS.Contains(str) ||
x.DATE_CREATE.ToString().Contains(str)));
var test = res.FirstOrDefault().DATE_CREATE.ToString();
}
finally
{
Thread.CurrentThread.CurrentCulture = originalCulture;
}
}
This will be enough if your input will have always dd/MM/yyyy format.
Edit:
You can try to use custom format string in ToString() call to achieve a working code as #bitapinches suggests. I think my solution performs better because there is no need to parse the custom format string in each comparison LINQ will execute. Here is the alternative for reference:
if (!string.IsNullOrEmpty(search))
{
List<string> terms = search.Split(',').ToList().ConvertAll(d => d.ToLower());
res = res.Where(x =>
terms.Any(
str => x.NAME.Contains(str) ||
x.ADDRESS.Contains(str) ||
x.DATE_CREATE.ToString(#"dd\/MM\/yyyy").Contains(str)));
var test = res.FirstOrDefault().DATE_CREATE.ToString();
}
I think cast datatime to date ToString() you need to convert date format like "dd/MM/yyyy" which is the parameter (search=20/01/2021) in your url then Here [x.DATE_CREATE.ToString().Contains(str)] i would use "equals" be like [x.DATE_CREATE.ToString("dd/MM/yyyy").equals(str)] to be more specific on the query.

Inconsistent datetime across server

I have a MVC function like this below, which will return the serialized JSON object back to the client:
public ActionResult ReportSalesHeaderListRest(ReportSalesRestViewModel viewModel, int? shop)
{
List<ReportGeneralDetailDto> rptSalesHeaderList = (
from txSalesHeader in completedTxSalesHeaderList.OrderBy(x => x.TxCode)
select new ReportGeneralDetailDto
{
ItemDate = txSalesHeader.CashierDatetime,
ItemCode = txSalesHeader.TxCode,
ItemValue = txSalesHeader.AmountTotal
})
.ToList();
viewModel.RptGeneralDetailList = rptSalesHeaderList;
return Json(viewModel, JsonRequestBehavior.AllowGet);
}
The problem is, JSON() function added some hours offset to my "ItemDate" attribute, when I run this code on an Asia server, 8 hours will be added to it, so "05/04/2014 08:15:19 (dd/mm/yyyy)" will become "Date(1396685719823)", which is "Sat Apr 05 2014 16:15:19 GMT+0800" instead of the time I want.
Does anyone come across this problem and is there any way ask JSON() function not to add the offset to my datetime values? Thanks!
I think that this is an issue with servers being in different time zones. You can use the DateTime.ToLocalTime() and DateTime.ToUniversalTime() to make the necessary conversion.

Setting a DateTime appointment schedule

Newbie question about using the DateTime method to set a schedule inside a Telerik calendar. I want to use the Telerik controls calendar to set a schedule for a music bands tour schedule.
I can't seem to get the desired results. Below is the code in my SampleAppointmentSource CS file. I thought that by setting the DateTime.Parse("5/19/2013") that then in all of the appointments when I use the AddDays(1) or AddDays(20) the appointemnts would follow the DateTime.Parse("5/19/2013") pattern but it doesn't. The appointments always use the current date and time (Now). When I add the days, the appointments aren't added to the Parsed date ("5/19/2013"), they are added to the current DateTime. Like the appointments are always referenced to the current system date.
I hope that wasn't to confusing....
What do I need to use to get the desired results?
Is it because of the DateTime.Now.AddDays(1) line? Should it not be DateTime.Now?
{
public class SampleAppointmentSource : AppointmentSource
{
public SampleAppointmentSource()
{
DateTime date = new DateTime();
date = DateTime.Parse("5/19/2013");
}
public override void FetchData(DateTime startDate, DateTime endDate)
{
this.AllAppointments.Clear();
this.AllAppointments.Add(new SampleAppointment()
{
StartDate = DateTime.Now.AddDays(1),
EndDate = DateTime.Now.AddDays(1),
Subject = "Jackson W/Warren Hayes",
AdditionalInfo = "Fain Feild",
Location = "LoserVille,Kentucky",
});
Fleshing out my comment to your question. You create a DateTime object called date and never use it. DateTime.Now will always return an object containing the current DateTime. You need give your date DateTime object module Level scope so you can access it in your FetchData method. See if something like this works for your.
public class SampleAppointmentSource : AppointmentSource
{
DateTime date;
public SampleAppointmentSource()
{
date = DateTime.Parse("5/19/2013");
}
public override void FetchData(DateTime startDate, DateTime endDate)
{
this.AllAppointments.Clear();
this.AllAppointments.Add(new SampleAppointment()
{
StartDate = date.AddDays(1),
EndDate = date.AddDays(1),
Subject = "Jackson W/Warren Hayes",
AdditionalInfo = "Fain Feild",
Location = "LoserVille,Kentucky",
});
}
}

Categories