How i can extract year from datetime.now? - c#

I want user to input the year of vehicle made but not more than this year. for example today is 2015, i don't want them to input 2020. but 2016 is ok.
here is my code.
property = validationContext.ObjectType.GetProperty("VehicleYear");
string vehicleYear = Convert.ToString(property.GetValue(validationContext.ObjectInstance, null));
if (!string.IsNullOrWhiteSpace(vehicleYear) && vehicleYear.Length == 4 && Convert.ToInt16(vehicleYear) >= 1980)
{
isVehicleOlderThan1981 = true;
}
else
{
isVehicleOlderThan1981 = false;
else if (value != null && Convert.ToDateTime(value) < DateTime.Now)
{
return new ValidationResult(this.ErrorMessage);
}
i only want to get a year from the DatetTime.now
Sorry i am new to the programming.

To get the year component of any date (including DateTime.Now), use this:
DateTime.Now.Year

I tried to clean your code for a bit and make it more logical (Also attached the answer you are looking for):
property = validationContext.ObjectType.GetProperty("VehicleYear");
var value = property.GetValue(validationContext.ObjectInstance, null);
int inputNumber;
//First check if input is number
if (!int.TryParse(value, out inputNumber))
{
this.ErrorMessage = "Input is not an integer!"
//you could also throw an exception here (depends on your error handling)
return new ValidationResult(this.ErrorMessage);
}
//retrieves the number of digits
int countDigits = Math.Floor(Math.Log10(year) + 1);
if (countDigits != 4)
{
this.ErrorMessage = String.Format("Input has {0} digits!",countDigits);
return new ValidationResult(this.ErrorMessage);
}
if (inputNumber > (DateTime.Now.Year + 1))
{
this.ErrorMessage = "Year is in the future!";
return new ValidationResult(this.ErrorMessage);
}
//inputNumber is now a valid year!
if(inputNumber > 1980)
{
isVehicleOlderThan1981 = true;
} else {
isVehicleOlderThan1981 = false;
}

Try this:
DateTime.Now.Year
You may also want to look at TryParse methods, it will simplify your code.
ie
int i;
if(int.TryParse("VehicleYear", out i)
{
//successful conversion, use int i for your comparisons etc.
}
else
{
//wasn't a valid year (can't be converted)
}

You need to use Year Year property from DateTime. Your else if may look like:
else if (value != null && Convert.ToDateTime(value).Year < DateTime.Now.Year)
NOTE: Convert.ToDateTime(value).Year will scream at you if value does not have correct date.

else if (value != null && Convert.ToDateTime(value) > DateTime.Now.AddYears(10))
{
//validation error
}

Related

Prevent double rounding in C# (and Blazor Server)?

This is my first question here.
I have a number value with the data type double, which rounds the decimal number before it is set in the setter. In the input field of the number only 20 characters are allowed (without comma). This is checked in the function "CheckInput" and the boolean is returned. However, since the number is rounded after the decimal point, I am unable to check for the number of characters correctly. Does anyone have any idea how to prevent automatic rounding on the double?
This is my double Property:
[Required]
[StringLength(20, ErrorMessage = "Es sind max. 20 Zeichen erlaubt (ohne Komma).")]
private double _xValue;
public double XValue
{
get => _xValue;
set
{
var oldValue = value;
_xValue= value;
if (!CheckInput(InputField.XValue))
{
_xValue= oldValue;
}
}
}
This is the function to check my input number:
public bool CheckInput(InputField inputField)
{
if (inputField == InputField.XValue || inputField == InputField.YValue)
{
var xWertDecimal = Convert.ToDecimal(XValue);
var yWertDecimal = Convert.ToDecimal(YWert);
var valueString = String.Empty;
if (inputField == InputField.XValue) valueString = xWertDecimal.ToString();
else if (inputField == InputField.YValue) valueString = yWertDecimal.ToString();
var splittedString = valueString.Split(',');
if (splittedString.Length == 2)
{
if (splittedString[0].Length + splittedString[1].Length > 20)
{
Snackbar.Add("Max. 20 Zeichen erlaubt!");
return false;
}
}
else if (splittedString.Length == 1)
{
if (splittedString[0].Length > 20)
{
Snackbar.Add("Max. 20 Zeichen erlaubt!");
return false;
}
}
return true;
}
else if (inputField == InputField.Haeufigkeit)
{
if (Haeufigkeit <= 0)
{
Snackbar.Add("Häufigkeit muss größer als 0 sein!");
return false;
}
return true;
}
else
{
return true;
}
}
No need to convert the numbers to Decimal for getting the string value.
You can just use the ToString() method of the double itself, and check the amount of digits there.
Here is a solution that would return the number of the digits of the double:
public static int GetDigitAmount(double numberToCheck)
{
// For more info on conversion see: https://learn.microsoft.com/en-us/dotnet/api/system.double.tostring?view=net-6.0
var strValue = numberToCheck.ToString("G", System.Globalization.CultureInfo.InvariantCulture);
return strValue.Length - (strValue.Contains(".") ? 1 : 0);
}
And here's the quickly adjusted version of your code:
public bool CheckInput(InputField inputField)
{
if (inputField == InputField.XValue || inputField == InputField.YValue)
{
double? valueToCheck = null;
if (inputField == InputField.XValue) valueToCheck = XValue;
else if (inputField == InputField.YValue) valueToCheck = YWert;
if (valueToCheck != null && GetDigitAmount(valueToCheck.Value) > 20) {
Snackbar.Add("Max. 20 Zeichen erlaubt!");
return false;
}
return true;
}
else if (inputField == InputField.Haeufigkeit)
{
if (Haeufigkeit <= 0)
{
Snackbar.Add("Häufigkeit muss größer als 0 sein!");
return false;
}
return true;
}
else
{
return true;
}
}
public static int GetDigitAmount(double numberToCheck)
{
// For more info on conversion see: https://learn.microsoft.com/en-us/dotnet/api/system.double.tostring?view=net-6.0
var strValue = numberToCheck.ToString("G", System.Globalization.CultureInfo.InvariantCulture);
return strValue.Length - (strValue.Contains(".") ? 1 : 0);
}
P.S. I didn't have a chance to test it as it requires the other code that you have on your end. If there's any error, please let me know.

i am working with c# DateTime and i need to get the .Hour property in it's 24 hour format

The If statement checking the hour always has a problem because my database returns a 24 hour format which returns false when 12pm <= 1pm.
here is the code:
public void SkippedDailyTask()
{
var pendingtasks = GetPendingTasks();
if (pendingtasks.Count() == 0)
{
Console.WriteLine("Empty List");
}
else
{
foreach (var item in pendingtasks)
{
if (item.EndTime.Hour <= DateTime.Now.Hour)
{
if (item.EndTime.Minute <= DateTime.Now.Minute)
{
item.StatusReturner = StatusReturner.Skipped;
}
else
{
Console.WriteLine("Empty List");
}
context.SaveChanges();
}
}
}
}
DateTime.Hour always returns the hour value in 24hr format as an integer. Check https://learn.microsoft.com/en-us/dotnet/api/system.datetime.hour?view=netframework-4.8
So if your item.EndTime.Hour returns 12 for 12:00PM and the current time is 1:00PM, the if (item.EndTime.Hour <= DateTime.Now.Hour) condition should return true as DateTime.Now.Hour will equal 13.
Also, not related to your question but, you are checking the count of pendingTasks using pendingtasks.Count(). In C#, length/count of iterables are implemented as properties rather than methods.
public void SkippedDailyTask()
{
var pendingtasks = GetPendingTasks();
if (pendingtasks.Count() == 0)
{
Console.WriteLine("Empty List");
}
else
{
foreach (var item in pendingtasks)
{
var hourNow = Convert.ToInt32(DateTime.Now.ToString("HH"));
// var hourItem = item.EndTime.Hour;
var hourItem = Convert.ToInt32(item.EndTime.ToString("HH"));
if (hourItem <= hourNow)
{
if (item.EndTime.Minute <= DateTime.Now.Minute)
{
item.StatusReturner = StatusReturner.Skipped;
}
else
{
Console.WriteLine("Empty List");
}
context.SaveChanges();
}
}
}
}

ASP.Net - Mvc5 : LINQ , Saving duplicate record problem

I am coding daily counter. Database Counter Table is empty. If someone is my first visitor of current day, then I am adding a record to database and i am setting counter=1; After this, when other visitor visit current day, then i am increasing my counter++ and i am updating the record.
So I my records must be like this:
Date:2018-10-01 counter:23
Date:2018-10-02 counter:65
Date:2018-10-03 counter:20
Date:2018-10-04 counter:89
My problem is this: If the site get visitor same time, linq save 2 record for same day. Like this:
Date:2018-10-01 counter:23
Date:2018-10-02 counter:1 //First record: counter=1
Date:2018-10-02 counter:65 //Second record: counter=65
Date:2018-10-03 counter:20
Date:2018-10-04 counter:1 //First record
Date:2018-10-04 counter:89 //second record
Date must be unique. How can I resolve this problem? My code is below. Thanks a lot.
public static int IncreaseCounter_DailySiteVisitors()
{
int counter = 0;
using (var context = new MyProjectEntities())
{
try
{
string format = "dd.MM.yyyy";
DateTime Today = DateTime.Now;
var obj = (from record in context.CounterDailySiteVisitor
where
record.DateRecord != null
&& record.DateRecord.HasValue
&& record.DateRecord.Value.Year == Today.Year
&& record.DateRecord.Value.Month == Today.Month
&& record.DateRecord.Value.Day == Today.Day
select record).FirstOrDefault();
//var obj = context.CounterDailyVisitor.Where(x => x.DateRecord != null && ((DateTime)x.DateRecord).ToString("yyyy.MM.dd") == DateTime.Now.ToString("yyyy.MM.dd")).FirstOrDefault();
if (obj != null)
{
counter = obj.Count ?? 0;
counter++;
obj.Count = counter;
context.SaveChanges();
}
else
{
var newRecordObj = context.CounterDailySiteVisitor.Create();
newRecordObj.Count = 1;
newRecordObj.DateRecord = Today;
context.CounterDailySiteVisitor.Add(newRecordObj);
context.SaveChanges();
}
}
catch (Exception e)
{
}
}
return counter;
}
the chances of this being hit by two thread at the same time is quite low.
but i guess technically it can so you would need to wrap this in a lock
Something like below...
public static int IncreaseCounter_DailySiteVisitors()
{
private readonly object somethingObject = new object();
var context = new MyProjectEntities()
var today = DateTime.Now;
var todaysRecord = context.CounterDailyVisitor
.SingleOrDefault(x => x.DateRecord.Year == Today.Year
&& x.DateRecord.Month == Today.Month
&& x.DateRecord.Day == Today.Day
);
if (todaysRecord != null)
{
//the existing count + 1
todaysRecord.Count = todaysRecord.Count++;
}
else
{
Lock(somethingObject)
{
//recheck
var todaysRecord = context.CounterDailyVisitor
.SingleOrDefault(x => x.DateRecord.Year == Today.Year
&& x.DateRecord.Month == Today.Month
&& x.DateRecord.Day == Today.Day
);
if (todaysRecord != null)
{
//the existing count + 1
todaysRecord.Count = todaysRecord.Count++;
}
else
{
var newRecordObj = new CounterDailyVisitor();
newRecordObj.Count = 1;
newRecordObj.DateRecord = DateTime.Now; //this shouldnt be nullable
context.CounterDailySiteVisitor.Add(newRecordObj);
}
}
}
context.SaveChanges();
}
This is quite a common concurrency problem i.e. race condition. You will either have to Lock around the code that reads and subsequently updates/inserts the value. Or you should call a stored procedure and have all the logic inside the stored proc.
Lock comes with it's own set of issues if you're planning on using a web farm or running multiple instances of this MVC app.

C# If Statement with value from field in Table

How do I write this statement to get a value back from the database or table and validate that if the Value = Yes it will return the "Result =10" part. The field is called "ApprovedStatus" the value will either be "No" or "Yes".
Visual Studio Tells me this: "The name 'Yes' does not exist in the current context"
If (ApprovedStatus.Equals = Yes)
{
result = 10;
}
else
{
result = 1;
}
Try if (ApprovedStatus == "Yes") if it's a string, or if (ApprovedStatus) if it's a bool.
If ApprovedStatus is of type bool, do:
if (ApprovedStatus)
Should it be string, do NOT do this
if(ApprovedStatus == "Yes")
because this will equal false if ApprovedStatus = "yes"
Instead use
if(StringComparer.OrdinalIgnoreCase.Equals(ApprovedStatus,"Yes"))
result = 10;
else
result = 1;
Note that if you do
if (ApprovedStatus.ToString().ToUpper().Equals("YES"))
or
if( ApprovedStatus.Equals("whatever",StringComparison.OrdinalIgnoreCase))
it will throw a null reference exception if ApprovedStatus is null.
...which is possible to likely if the value comes from a database.
Best guess given the limited info available... (Assuming ApprovedStatus is a String)
if(ApprovedStatus == "Yes")
{
result = 10;
}
else
{
result = 1;
}
or
if(ApprovedStatus.Equals("Yes"))
{
result = 10;
}
else
{
result = 1;
}
Use String.Compare -- it's more efficient.
if(String.Compare(ApprovedStatus, "Yes", true)==0){
result = 10;
} else {
result = 1;
}
Boolean values in C# are true and false. You should consult a basic C# tutorial, but your check has probably to look like this:
if (ApprovedStatus)
{
result = 10;
}
else
{
result = 1;
}
It can be written shorter as:
result = ApprovedStatus ? 10 : 1;
if (ApprovedStatus.Equals("Yes")) <-- Case Sensitive
{
}
or
if (ApprovedStatus.ToString().ToUpper() == "YES")
{
}

Can anyone simplify this Algorithm for me?

Basically I just want to check if one time period overlaps with another.
Null end date means till infinity. Can anyone shorten this for me as its quite hard to read at times. Cheers
public class TimePeriod
{
public DateTime StartDate { get; set; }
public DateTime? EndDate { get; set; }
public bool Overlaps(TimePeriod other)
{
// Means it overlaps
if (other.StartDate == this.StartDate
|| other.EndDate == this.StartDate
|| other.StartDate == this.EndDate
|| other.EndDate == this.EndDate)
return true;
if(this.StartDate > other.StartDate)
{
// Negative
if (this.EndDate.HasValue)
{
if (this.EndDate.Value < other.StartDate)
return true;
if (other.EndDate.HasValue && this.EndDate.Value < other.EndDate.Value)
return true;
}
// Negative
if (other.EndDate.HasValue)
{
if (other.EndDate.Value > this.StartDate)
return true;
if (this.EndDate.HasValue && other.EndDate.Value > this.EndDate.Value)
return true;
}
else
return true;
}
else if(this.StartDate < other.StartDate)
{
// Negative
if (this.EndDate.HasValue)
{
if (this.EndDate.Value > other.StartDate)
return true;
if (other.EndDate.HasValue && this.EndDate.Value > other.EndDate.Value)
return true;
}
else
return true;
// Negative
if (other.EndDate.HasValue)
{
if (other.EndDate.Value < this.StartDate)
return true;
if (this.EndDate.HasValue && other.EndDate.Value < this.EndDate.Value)
return true;
}
}
return false;
}
}
public bool Overlaps(TimePeriod other)
{
return (other.StartDate >= StartDate &&
(EndDate == null || other.StartDate <= EndDate.Value)) ||
(StartDate >= other.StartDate &&
(other.EndDate == null || StartDate <= other.EndDate.Value))
}
How about this one:
public bool Overlaps(TimePeriod other)
{
bool isOtherEarlier = this.StartDate > other.StartDate;
TimePeriod earlier = isOtherEarlier ? other : this;
TimePeriod later = isOtherEarlier ? this : other;
return !earlier.EndDate.HasValue || earlier.EndDate > later.StartDate;
}
Check this out: DateTimeOverlaps
Very generally, if all variables are nullable datetimes, then
return (StartA.HasValue? StartA.Value:DateTime.Minimum) <=
(EndB.HasValue? EndB.Value:DateTime.Maximum) &&
(EndA.HasValue? EndA.Value:DateTime.Maximum) >=
(StartB.HasValue? StartB.Value:DateTime.Minimum);
The concept, (as explained in link) is very simple, and is simply and concisely expressed above.
If the start is before the others end, and the end is after the other start, you have overlap. This says it all, and all that is necessary, in one simple sentence with two clauses, and whatever code you write should concisely map to that simple concept without obfuscating it. Adding extra unecessary complexity does not add understanding, it only adds length.
Fail Case 1: TopStart AFTER other End - Fail
|----------|
|--|
Fail Case 2: TopEnd AFTER other start - Fail
|-----------|
|------|
In all other cases, start is before other end, and end is after other start.
case A
|----------|
|-----|
case B
| ---------|
|-------------------|
case C
|-----------|
|------|
case D
|-----------|
|-------------|
Any time you're dealing with pure boolean logic, you can distill your algorithm down to a single statement. But don't assume that just because you can, you should. Unless performance is vital, always go for readable code over compact code. (Not that compactness == performance, necessarily)
This is easy to read because it's comprised entirely of single AND expressions, and it's obvious that they all determine a non-overlap:
public bool Overlaps(TimePeriod other)
{
if (other.EndDate.HasValue && other.EndDate < StartDate)
return false;
if (EndDate.HasValue && EndDate < other.StartDate)
return false;
if (!EndDate.HasValue && other.EndDate < StartDate)
return false;
if (!other.EndDate.HasValue && EndDate < other.StartDate)
return false;
return true;
}
Not that the other answers are bad (I like Adam's; his formatting is obviously designed to aid readability). I'm just saying this because it's clear you're a beginner, and I think this is one lesson that isn't heeded enough (I'm guilty). Somebody (I think Martin Fowler) once said something like: "Any fool can write code that a computer understands, but a good programmer can write code that a human understands."

Categories