So I have a program I use that I have become very intrigued by how they force their formatting of a date in a field when input. For example, if I put in "10217", the system would automatically force the field to become 10/02/2017. However, if I put in 1117, then nothing happens as it could be 01/01/2017, 11/17/??, or some other of many combinations. Does anyone know how this forced formatting might be being achieved regarding the logic?
Additionally, you can put in a date in the same field formatted as 10.2.17 and it would reformat to 10/2/2017. As well, if you input 1.1.17, it would reformat to 1/1/2017. Lastly, you can do the same thing of putting in the slashes and it will reformat the respective date format. So if I put in 10/2/17, it would reformat to 10/2/2017. Same this with typing 1/1/17 will reformat to 1/1/2017.
I've looked at the following link, but am not seeing anything that could be used to do this kind of logic. (Granted I could just be blatantly missing it.)
https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings
As well, I have seen this example surrounding a regex, but I am not familiar with this process.
Validating a date format string in c#
I understand this is a lot, but this all revolves around the date forced formatting logic. I am really not sure what logic to use to achieve what I want or what logic to chain together to achieve what I am looking for. I greatly appreciate all of the input.
I think to approach this problem it may be necessary to see what they are using to parse the input of the user. If they are using DateTime.Parse then it will throw an exception when the string being parsed is ambiguous.
Of course, a programmer could always create their own way of parsing the input in the field. Though, typically a programmer isn't that enthusiastic about dealing with the ambiguous cases when parsing information. So let's assume they are working with a DateTime.Parse method for simplicity sake.
I created the following program to allow you to see when the parser sees something as ambiguous. The output of the program is shown in this picture:
The code demonstrating DateTime.Parse:
static void Main(string[] args)
{
string input = "";
while(input != "exit" || input != "Exit")
{
Console.Write("Input: ");
input = Console.ReadLine();
string inputDate = input;
//try to parse it
try
{
DateTime date = DateTime.Parse(inputDate);
Console.WriteLine(date+"\n");
}
catch
{
//Exceptions. String not valid because ambiguity
Console.WriteLine("Ambiguous.\n");
//In here can also perform other logic, of course
}
}
}
In order to convert the DateTime back to a string you can do something similar to:
try
{
DateTime date = DateTime.Parse(inputDate);
Console.WriteLine(date+"\n");
string month = date.Month.ToString();
string day = date.Day.ToString();
string year = date.Year.ToString();
string resultingString = month + " " + day + " " + year ;
Console.WriteLine(resultingString);
}
catch(Exception e)
{
//Exceptions. String not valid because ambiguity
Console.WriteLine("Ambiguous");
}
You can even make your own parser with this information in this fashion so you can acheive a result for a date entered that is 3 characters long:
static void Main(string[] args)
{
string input = "";
while(input != "exit" || input != "Exit")
{
Console.Write("Input: ");
input = Console.ReadLine();
string inputDate = input;
try
{
DateTime date = DateTime.Parse(inputDate);
Console.WriteLine(date+"\n");
string month = date.Month.ToString();
string day = date.Day.ToString();
string year = date.Year.ToString();
string resultingString = month + " " + day + " " + year;
//string resultingString = month + "/" + day + "/" + year;
Console.WriteLine(resultingString);
}
catch(Exception e)
{
//Exceptions. String not valid because ambiguity
try
{
Console.WriteLine( myParser(inputDate) );
}
catch
{
Console.WriteLine("Ambiguous");
}
//Console.WriteLine("Ambiguous.\n");
//In here can also perform other logic, of course
}
}
}
static string myParser(string input)
{
string month,day,year,date;
switch (input.Length)
{
//In the case that it's 1 character in length
case 1:
return "Ambiguous.";
case 2:
return "Ambiguous.";
//did user mean #/#/200#? hopefully not #/#/199#...
case 3:
month = input.Substring(0, 1);
day = input.Substring(1, 1);
year = input.Substring(2, 1);
date = month + " " + day + " " + year;
return date;
//did user mean # # 20##
//or # ## 200#
//or ## # 200#
case 4:
return "Ambiguous";
//user probably means ## # ##
case 5:
return "Ambiguous";
case 6:
return "Ambiguous";
default:
return "Ambiguous";
}
}
Similarly, if you want to get the date back to a slash (/) seperated format in the form of a string without the minutes and hours and such..
case 3:
month = input.Substring(0, 1);
day = input.Substring(1, 1);
year = input.Substring(2, 1);
date = month + " " + day + " " + year;
DateTime dateTimeObj = DateTime.Parse(date);
month = dateTimeObj.Month.ToString();
day = dateTimeObj.Day.ToString();
year = dateTimeObj.Year.ToString();
string resultingString = month + "/" + day + "/" + year;
return resultingString;
Related
By Input i mean Console.ReadLine() and the way it got changed.
I tried to make a code that could count the days that the User inputed left in the same Year.
After that it should it should loop through the for loop.
This is what it should do.
The Output should be: The difference between the two Inputs, the amount of days it takes to end the year with the first Input in mind subtract that with the total amount and if it is more then 360 it should output the amount and subtract it with 360 so long until the it is under 360.
My Current Output is: 0 Days when numberOfDays is Outputed and when NumberOfDays2 is outputed the Output is 363.
My Problem is that i dont know what exactly the problem is in my Code.
It would be a great help if someone could explain to me where the Problem is or what the root of the Problem is.
Rightnow im very confused do to the comparison with my other code i made where parts like (.TotalDays) perfectly worked.
I would like to know why it doesnt work because in theory it should work.
internal class Program
{
static void Main(string[] args)
{
//Input and Visual
Console.WriteLine("write here Beginning");
Console.Write("Day: ");
string FirstDay = Console.ReadLine();
Console.Write("Month:");
string StillFirstDay = Console.ReadLine();
Console.Write("Year:");
string Still_FirstDay = Console.ReadLine();
Console.Clear();
Console.WriteLine("Beginn: " + FirstDay + "." + StillFirstDay + "." + Still_FirstDay);
Console.WriteLine("");
Console.WriteLine("write here End ");
Console.Write("Day: ");
string LastDay = Console.ReadLine();
Console.Write("Monat:");
string StillLastDay = Console.ReadLine();
Console.Write("Jahr:");
string Still_LastDay = Console.ReadLine();
//Prepare
int input = 0;
int IFirstDay = 1;
int IStillFirstDay = 1;
int IStill_FirstDay = 1;
int ILastDay = 1;
int IStillLastDay = 1;
int IStill_LastDay = 1;
JustforConversion(FirstDay, input, IFirstDay);
JustforConversion(StillFirstDay, input, IStillFirstDay);
JustforConversion(Still_FirstDay, input, IStill_FirstDay);
JustforConversion(LastDay, input, ILastDay);
JustforConversion(StillLastDay, input, IStillLastDay);
JustforConversion(Still_LastDay, input, IStill_LastDay);
DateTime date1 = new DateTime(IStill_LastDay, IStillLastDay, ILastDay);
DateTime date2 = new DateTime(IStill_FirstDay, IStillFirstDay, IFirstDay);
var numberOfDays = (date2 - date1).TotalDays;
Console.WriteLine(numberOfDays);
int Year = IStill_FirstDay - IStill_LastDay;
DateTime date3 = new DateTime(IStillFirstDay, 12, 30);
var numberOfDays1 = (date3 - date2).Days;
Console.WriteLine(numberOfDays1);
var numberOfDays2 = numberOfDays - numberOfDays1;
Console.WriteLine("In Year 1 there were " +numberOfDays1+" Days.");
for (int i = 2; i <= Year; i++)
{
if (numberOfDays2 > 360)
{
Console.WriteLine("In Year " + i + " there were " + numberOfDays2 + " Days.");
numberOfDays2 -= 360;
}
else
{
Console.WriteLine(numberOfDays2);
break;
}
}
Console.ReadKey();
}
static void JustforConversion(string Converted,int Zero,int Complete_Convert)
{
while (int.TryParse(Converted, out Zero))
{
Complete_Convert = Convert.ToInt32(Converted);
break;
}
}
}
}
Your JustforConversion() method has so many things wrong with it, but the biggest problem is that it doesn't actually "return" anything. ints are passed "by value", which means a copy is made; the original variable is NOT changed after the call to JustforConversion().
It looks like you were expecting the "Ixxx" variables to have valid integers in them after the calls. You'd need to declare that parameter as an out parameter for this to work:
static void Main(string[] args)
{
string FirstDay = "10";
int IFirstDay = 1;
Console.WriteLine("Before JustforConversion():");
Console.WriteLine("IFirstDay = " + IFirstDay);
JustforConversion(FirstDay, out IFirstDay);
Console.WriteLine("After JustforConversion():");
Console.WriteLine("IFirstDay = " + IFirstDay);
}
static void JustforConversion(string Converted, out int IConverted)
{
IConverted = int.Parse(Converted);
}
Output:
Before JustforConversion():
IFirstDay = 1
After JustforConversion():
IFirstDay = 10
I'm trying to add days or month to a datetime. What determines rather it should add days or month to the datetime is what dayOrMonth ends with. So for example if dayOrMonth ends with MM it should add month, if it ends with DD it should add days.
dayOrMonth could look like this "90DD" (should add 90 days) and "90MM" should add 90 month.
I'm thinking about creating an extension method of some kind, but I'm struggling abit with the approach to this, as adding more if statements is not an option.
//... Set payment dates.
string dayOrMonth;
for (int x = 0; x < installmentDates.Count; x++)
{
if (installmentDates.Count > 0)
{
installmentdDateRow[colName] = installmentdDateRow[colName] + Convert.ToDateTime(installmentDates[x]).ToString("dd'-'MM'-'yyyy") + "\n";
//... Future payment dates.
int futurePaymentColumn = installmentdFuturePayments.Table.Columns.IndexOf(colName);
if (colName == "1. rate" && installmentDates.Count - 1 == x)
{
installmentdFuturePayments[futurePaymentColumn + 1] = installmentdFuturePayments[futurePaymentColumn + 1] + Convert.ToDateTime(installmentDates[x]).AddMonths(3).ToString("dd'-'MM'-'yyyy") + "\n";
}
if (colName == "2. rate" && installmentDates.Count - 1 == x && Functions.GetProductInfo(unit.Key.ToString().Split('-')[0])[9] != "€ 0,00")
{
installmentdFuturePayments[futurePaymentColumn + 1] = installmentdFuturePayments[futurePaymentColumn + 1] + Convert.ToDateTime(installmentDates[x]).AddMonths(3).ToString("dd'-'MM'-'yyyy") + "\n";
}
}
}
You have described an input string composed of two parts:
An integer magnitude to apply to some operation
A two character string defining the operation to use
As such, you know there should always be at least three characters. You also know the trailing two characters define the operation, so you can use Substring to separate those characters from the rest of the string.
An extension method is a great idea. It should include tests to help enforce the format of the input string, and make it easy to parse the numeric component.
public static DateTime ApplyInput(this DateTime dt, string input)
{
if (input == null)
{
throw new ArgumentNullException(nameof(input), "The input string must not be null.");
}
if (input.Length < 3)
{
throw new ArgumentException("The input string is too short to include both a number and an operation.", nameof(input));
}
string numberChars = input.Substring(0, input.Length - 2);
if (!int.TryParse(numberChars, out int number))
{
throw new ArgumentException("The start of the input string must be an integer.", nameof(input));
}
string endingChars = input.Substring(input.Length - 2);
switch (endingChars.ToUpperInvariant())
{
case "MM":
return dt.AddMonths(number);
case "DD":
return dt.AddDays(number);
default:
throw new ArgumentException($"The characters {endingChars} were not recognized as a valid operation.", nameof(input));
}
}
This approach will perform better than using RegEx, Contains, or Replace. It is also extensible by adding more case statement to the switch.
Note that .ToUpperInvariant() makes the operation characters case-insensitive so you can pass mm or dd if you like. If you don't wan't that behavior, then simply remove .ToUpperInvariant().
Using StackOverflow - Seperating characters and numbers
You can use a regular expression to seperate the numbers from the characters in a given string like so:
Regex re = new Regex(#"([a-zA-Z]+)(\d+)");
Match result = re.Match(input);
string alphaPart = result.Groups[1].Value;
string numberPart = result.Groups[2].Value;
Then you can create a factory method or a project wide reference where you can use that code snippet to achieve what youre asking:
public DateTime AddDaysOrMonths(string input, DateTime dt)
{
Regex re = new Regex(#"([a-zA-Z]+)(\d+)");
Match result = re.Match(input);
string alphaPart = result.Groups[1].Value;
string numberPart = result.Groups[2].Value;
if(alphaPart == "DD")
{
int days;
if(Integer.TryParse(numberPart,out days) == true)
{
dt.AddDays(days)
}
}
else if (alphaPart == "MM")
{
int months;
if(Integer.TryParse(numberPart,out months) == true)
{
dt.AddMonths(months);
}
}
return dt;
}
Ofcourse, you should implement more extenstive error/null checking and better string comparison but this should be enough to get you going in the right direction.
I solved my problem by creating this extension method
public static DateTime test1(this DateTime d, string inputType)
{
if (inputType.Contains("DD"))
{
d = d.AddDays(Convert.ToInt32(inputType.Replace("DD", "")));
}
if (inputType.Contains("MM"))
{
d = d.AddMonths(Convert.ToInt32(inputType.Replace("MM", "")));
}
return d;
}
This will be a noobish question but I am currently working on a program that will take in a user input in the format of DD/MM/YYYY and the output it in the format 1st of May 2017, for example.
But whenever the use string.substring (UserInput.substring in my case) it does not separate the values correctly. For example, when I input the date as 21/05/2001 it displays 215 2001. I have no idea why this is happening.
Im sorry as this is very noobish but I am new to using .substring and I'm sure the problem will seem obvious when someone points it out xD
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DateProgram
{
class Program
{
static void Main(string[] args)
{
/// Define Varibles
string UserIntput;
int Day;
int Month;
int year;
///Gathering UserInput
Console.Write("Please enter the date in the format dd/mm/yyyy");
UserIntput = Console.ReadLine();
///Validations
try
{
while(UserIntput.Substring(2,1) != "/" || UserIntput.Substring(5,1) != "/" || UserIntput.Length != 10)
{
Console.WriteLine("Invalid Input");
Console.Write("Please enter the date in the format dd/mm/yyyy");
UserIntput = Console.ReadLine();
}
}
catch
{
Console.WriteLine("Invalid Input");
}
/// Defining to Variables
Day = Convert.ToInt32(UserIntput.Substring(0, 2));
Month = Convert.ToInt32(UserIntput.Substring(3, 2));
year = Convert.ToInt32(UserIntput.Substring(6, 4));
Console.WriteLine(Day + "" + Month + " " + year);
Console.ReadLine();
}
}
}
Pass your user input string in to a System.Convert.ToDateTime method:
DateTime dt = Convert.ToDateTime(UserIntput);
Then, if you would like to change the format of how it is presented, use one of the DateTime.ToString() overloads to convert it to the format you want. (Search for ToString() on this page)
It might look something like this:
dt.ToString("MM-dd-yyyy", System.Globalization.CultureInfo.InvariantCulture);
You'll also want to review this page: Custom Date and Time Format Strings
Use ParseExact like this:
using System;
public class Program
{
public static void Main()
{
DateTime? dt = null;
do
{
Console.WriteLine("Input date: (dd/MM/yyyy)");
var input = Console.ReadLine();
try
{
dt = DateTime.ParseExact(input, "dd/MM/yyyy", System.Globalization.CultureInfo.InvariantCulture);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
} while (!dt.HasValue);
Console.WriteLine(dt.Value.ToString("F"));
var myDate = dt.Value;
// access the single fields from the parsed object
Console.WriteLine(myDate.Day);
Console.WriteLine(myDate.Month);
Console.WriteLine(myDate.DayOfWeek);
Console.WriteLine(myDate.Year);
}
}
See https://dotnetfiddle.net/TeYSF7
In addition to the "custom" link for DateTime-Formatting (see BobbyA's answer), consider these which come by default: standard-date-and-time-format-strings
Using string.Split(..) - although why if DateTime comes with valid ways to parse.
var parts = "22/12/2012".Split(new []{'/'}, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 3)
{
var day = int.Parse(parts[0]); // will crash if not an int - use .TryParse(...) or handle error
var month = int.Parse(parts[1]); // will crash if not an int
var year = int.Parse(parts[2]); // will crash if not an int
var date = new DateTime(day,month,year)) // will crash if f.e. 45.24.788
}
else
{
// invalid input
}
Try parsing date and time with a help of DateTime.TryParseExact which has been specially designed for such tasks:
using System.Globalization;
...
DateTime userDate;
// Gathering UserInput (just one simple loop)
do {
Console.WriteLine("Please enter the date in the format dd/mm/yyyy");
}
while (!DateTime.TryParseExact(Console.ReadLine(),
"d/m/yyyy", // be nice, let 21.5.2017 be valid; please, do not inist on 21.05.2017
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeLocal,
out userDate));
// If you insist on these local variables:
int day = userDate.Day;
int month = userDate.Month;
int year = userDate.Year;
// But I suggest formatting or string interpolation:
Console.WriteLine($"{userDate:dd MM yyyy}");
Assuming you want to keep your current approach (instead of using any of the built-in functions provided in the other answers), your problem is just a typo.
Change this:
Console.WriteLine(Day + "" + Month + " " + year);
To this:
Console.WriteLine(Day + " " + Month + " " + year); //Notice the space
In the future, you can avoid this sort of problem by using a constant:
const string space = " ";
Console.WriteLine(Day + space + Month + space + year);
public string completeHour(string theTime)
{
string total="";
string[] timeArray = theTime.Split(new[] { ":" }, StringSplitOptions.None);
string h = timeArray[0];
string i = timeArray[1];
string j = timeArray[2];
MessageBox.Show(h + "+" + i + "+" + j);
if (h == " " || i == " " || j == " ")
{
if (h == " ")
{
h = "00";
total = (String.Concat("00",theTime)).Trim();
MessageBox.Show(total);
}
else if (i == " ")
{
i = "00";
total = timeArray[0] + i + timeArray[2];
//MessageBox.Show("m-=" + total);
}
//else if (j == "")
//{
// j = "00";
// theTime = timeArray[0] + timeArray[1] + j;
// MessageBox.Show("s-=" + theTime);
//}
}
return total;
}
Why total is 00 :52:04 (for instance) and not 00:52:04 that was supposed to be?
If you'd like to make sure there are no leading or trailing white characters, you could call
string h = timeArray[0].Trim();
And then instead of checking the value against " ", you could compare it to String.Empty or call h.IsNullOrEmpty().
However I'd strongly recommend you to use simpler approach, using a DateTime object.
DateTime timeObject;
DateTime.TryParse(theTime, out timeObject);
and then just work with Hour, Minute and Second properties. This way you get away from custom parsing and make your code more object-oriented, thus easier to read, instead of juggling multiple string objects.
Best way to avoid this is using Trim() when assigning value to total in following two lines:
total = (String.Concat("00",theTime.Trim())).Trim();
.
.
.
total = timeArray[0].trim() + i + timeArray[2].Trim();
Although I was using a MaskedTextBox I didn't define a custom mask so, anywhere (I think) the system assumed that 'theTime' was the type of DateTime.
So, the result of String.Concat("00",theTime) was '00 :32:99', for instance.
I´ve solved it by using the variables h, i and j instead of theTime.
Using a DateTime variable was not appropriated because I want to allow the user to insert NULL values for the hours or for the minutes.
i made a small parser that will go though a message and replace $user with a certain user and so on.
besides the basic keywords, i wanted it to replace dates like this:
$datemo10 with todays date plus 10 months
$datedd03 with todays date plus 3 days
$datehh07 with todays date plus 7 hours
$datemm12 with todays date plus 12 minutes
$datess15 with todays date plus 15 seconds
This is what i got working..
const string Identifier = "$";
const string TimeFormat = "HH:mm:ss dd-MM-yyyy";
public static string Encode(string Author, string Recipent, string input)
{
Dictionary<string, string> keywords = new Dictionary<string, string>();
keywords.Add("bye", "With kind regards " + identify("me"));
keywords.Add("user", Recipent);
keywords.Add("me", Author);
keywords.Add("now", DateTime.Now.ToString(TimeFormat));
keywords.Add("date", "");
string result = input;
foreach (KeyValuePair<string, string> keyword in keywords)
{
if (keyword.Key.ToLower() == "date")
{
int addedLength = 0;
foreach (Match match in Regex.Matches(input, "\\" + identify(keyword.Key)))
{
string mode = input.Substring(match.Index + addedLength + match.Length, 2);
string stringInteger = input.Substring(match.Index + addedLength + match.Length + 2, 2);
int integer;
if (int.TryParse(stringInteger, out integer) && !mode.Contains(" "))
{
if (mode == "ss")
{
string dateTime = DateTime.Now.AddSeconds(Convert.ToDouble(integer)).ToString(TimeFormat);
input = input.Remove(match.Index + addedLength, match.Length + 4);
input = input.Insert(match.Index + addedLength, dateTime);
addedLength += (dateTime.Length - (match.Length + 4));
}
else if (mode == "mm")
{
string dateTime = DateTime.Now.AddMinutes(Convert.ToDouble(integer)).ToString(TimeFormat);
input = input.Remove(match.Index + addedLength, match.Length + 4);
input = input.Insert(match.Index + addedLength, dateTime);
addedLength += (dateTime.Length - (match.Length + 4));
}
else if (mode == "hh")
{
string dateTime = DateTime.Now.AddHours(Convert.ToDouble(integer)).ToString(TimeFormat);
input = input.Remove(match.Index + addedLength, match.Length + 4);
input = input.Insert(match.Index + addedLength, dateTime);
addedLength += (dateTime.Length - (match.Length + 4));
}
else if (mode == "dd")
{
string dateTime = DateTime.Now.AddDays(Convert.ToDouble(integer)).ToString(TimeFormat);
input = input.Remove(match.Index + addedLength, match.Length + 4);
input = input.Insert(match.Index + addedLength, dateTime);
addedLength += (dateTime.Length - (match.Length + 4));
}
else if (mode == "mo")
{
string dateTime = DateTime.Now.AddMonths(integer).ToString(TimeFormat);
input = input.Remove(match.Index + addedLength, match.Length + 4);
input = input.Insert(match.Index + addedLength, dateTime);
addedLength += (dateTime.Length - (match.Length + 4));
}
else if (mode == "yy")
{
string dateTime = DateTime.Now.AddYears(integer).ToString(TimeFormat);
input = input.Remove(match.Index + addedLength, match.Length + 4);
input = input.Insert(match.Index + addedLength, dateTime);
addedLength += (dateTime.Length - (match.Length + 4));
}
}
}
}
else
{
input = Regex.Replace(input, "\\" + identify(keyword.Key), keyword.Value);
}
}
return input;
}
protected static string identify(string val)
{
return Identifier + val;
}
I feel fine about keeping the keywords that needs to be replaced in a dictionary, but i really dont like the way im parsing and replacing the dates.
But as im pretty new to the whole programming world, this is the only way i was able to make it work. Though im perfectly able to see why it could be so much better, if you have any idea on how to make it work in a less hacky way, please tell me :)
Tear it apart, but please do so in a constructive matter.
How can i make it better?
I know there is quite a bit repetitive code.. Shhh
Thanks :)
I would suggest looking through http://msdn.microsoft.com/en-us/library/system.timespan.aspx
and the other msdn libraries for more info on what you are trying to do. They have great examples and all the information on all the .net libraries.
Well for starters you should make that repetitive code into its own function just so your not repetitive, I find I am doing something wrong if I ever touch the ctrl+c key more than once while I am programming.
Also, are you just getting the current date and adding time to each hour minuet ext ext. If your adding an amount of time to each date I think you can do it much more easily
I thought there was a general datetime.add function for c# that you could use to add
a timespan. The timespan being made up of all the $datedd03 $datehh07 parts. I am still learning c# so I am not that good with c# so Someone more experienced with datetime should be able to help more
The link at the top has the info about the timespan function.