Batch script that can update a file with a date range - c#

I need some assistance changing a date range on line 13 of a file:
01/01/201101/31/2011
I plan on setting the script to run every day from the windows scheduler.
I would like the script to change the begining date -15 days from current date
and the ending date +15 days from the current date.
I found the DateAdd.cmd written by Rob van der Woude (http://www.robvanderwoude.com)
but I am not sure how to pass the values back to my main (calling) script?

Without any ~batch~ assistance, I did the following in C#:
static void Main(string[] args)
{
string inputFile = Path.Combine("C:/temp","textfile.txt");
string outputFile = Path.Combine("C:/temp","textfile2.txt");
using(StreamReader input = File.OpenText(inputFile))
using(Stream output = File.OpenWrite(outputFile))
using(StreamWriter writer = new StreamWriter(output))
{
int count = 1;
while(!input.EndOfStream)
{
// read line
string line = input.ReadLine();
// Get dates 15 days on either side of current date
if(count == 13)
{
DateTime beginRange = DateTime.Today.AddDays(-15);
DateTime endRange = DateTime.Today.AddDays( 15 );
string strBeginDate = beginRange.ToShortDateString();
string strEndDate = endRange.ToShortDateString();
// replace line with new date range
line = "0001" + strBeginDate + strEndDate + "Report submitted by";
}
// increment counter
count++;
// write the file to temp file
writer.WriteLine(line);
}
}
File.Delete(inputFile); // delete original file
File.Move(outputFile,inputFile); // rename temp file to original file name

The batch file language hasn't been significantly updated decades. You still can't do a conventional for loop. I suggest looking into PowerShell. It is just as powerful (if not more) than the *nix shell languages, but can also leverage the entire .NET framework. If you use PowerShell, this problem would be as simple as
Open file, go to line 13
Parse the line as two dates
Subtract 15 days from one date object and add 15 to the next
Write the file back out
The fact that you're trying to do real programming in a batch file is truly honorable (I would have commited Seppuku). Try to switch to a more powerful shell language that is more feature complete. Besides, PowerShell is the future of Windows scripting.

I found the DateAdd.cmd written by Rob van der Woude (http://www.robvanderwoude.com) but I am not sure how to pass the values back to my main (calling) script?
I would agree with others that you're better off using a different scripting language (VBS, PowerShell, ...), but to answer this specific question, the DateAdd.cmd batch file sets an environment variable DATEADD to the result of its deliberations.
You can do something like:
CALL DATEADD -15 >NUL:
SET FROMDATE=%DATEADD%
CALL DATEADD 15 >NUL:
SET TODATE=%DATEADD%
echo %FROMDATE%%TODATE%
Note that DateAdd.cmd uses the current user's short date format from the registry, so will give different results depending on the user's locale.

Related

selecting dates greater than from xml using C#

I am getting myself confused in Powershell in trying to use C# to fill a spreadsheet with two columns. The first is "start" and is what I need help with most. I want this to populate with dates greater than 31st July of a given year as entered as a string at the start. The below is part of what i'm using, and the whole thing is giving me a spreadsheet, but just not the dates I need. It's the line that starts $dr = $DS.Tables which I have been tampering with but to no avail.
$fileyear = "2017";
###Location of default DLLs
$DllsDir = [System.IO.Path]::Combine($PSScriptRoot,"dlls")
Write-Output "Dll Path "+$DllsDir
###Load default DLLs
foreach ($dll in [System.IO.Directory]::GetFiles($DllsDir,"*.dll",
[System.IO.SearchOption]::AllDirectories))
{
[reflection.assembly]::loadfrom($dll);
}
Write-Output "Dlls loaded";
###declare objects
$DS = New-Object System.Data.DataSet;
$DS.ReadXml($DBPath,[System.Data.XmlReadMode]::Auto);
$dt = New-Object System.Data.DataTable;
$dt.Columns.Add("Start");
$dt.Columns.Add("ULIN");
$dr = $DS.Tables["LearningDelivery"].Select("LearnStartDate >
(31/07/"+$fileyear+")");
[datetime]$LearnStartDate = $dr["LearnStartDate"]
Write-Output $dt.Rows.Count;
I guess that the date is not in the correct format. The format depends on the region your machine is configured.
I would build the date using the ISO format. Check for example this question for a reference: DataTable.Select date format problem

File creation time in C#

I need to get when a file was created - I have tried using:
FileInfo fi = new FileInfo(FilePath);
var creationTime = fi.CreationTimeUtc;
and
var creationTime = File.GetCreationTimeUtc(FilePath);
Both methods generally return the wrong creation time - I guess it is being cached somewhere.
The file is deleted and re-created with the same name and I need to know when/if it has been re-created (by checking if the created date/time has changed) - I had planned to do this by seeing it the file creation time had changed but I have found this to be inaccurate.
I'm working on Win 7 and if I check File Explorer it shows the new file creation time correctly.
I have also tried using the FileSystemWatcher but it doesn't entirely work for my use case. E.g. if my program is not running, the FileSystemWatcher is not running, so when my program starts up again I don't know if the file has been deleted and recreated or not.
I've seen MSDN http://msdn.microsoft.com/en-us/library/system.io.file.getcreationtime.aspx where it says:
This method may return an inaccurate value, because it uses native functions whose values may not be continuously updated by the operating system.
But I have also tried using their alternative suggestion and setting the SetCreationDate after creating a new file but I also find that this doesn't work. See test below:
[Test]
public void FileDateTimeCreatedTest()
{
var binPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);
var fullFilePath = Path.Combine(binPath, "Resources", "FileCreatedDatetimeTest.txt");
var fullFilePathUri = new Uri(fullFilePath);
var dateFormatted = "2013-08-17T15:31:29.0000000Z"; // this is a UTC string
DateTime expectedResult = DateTime.MinValue;
if (DateTime.TryParseExact(dateFormatted, "o", CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal, out expectedResult)) // we expect the saved datetime to be in UTC.
{
}
File.Create(fullFilePathUri.LocalPath);
Thread.Sleep(1000); // give the file creation a chance to release any lock
File.SetCreationTimeUtc(fullFilePathUri.LocalPath, expectedResult); // physically check what time this puts on the file. It should get the local time 16:31:29 local
Thread.Sleep(2000);
var actualUtcTimeFromFile = File.GetCreationTimeUtc(fullFilePathUri.LocalPath);
Assert.AreEqual(expectedResult.ToUniversalTime(), actualUtcTimeFromFile.ToUniversalTime());
// clean up
if (File.Exists(fullFilePathUri.LocalPath))
File.Delete(fullFilePathUri.LocalPath);
}
Any help much appreciated.
You need to use Refresh:
FileSystemInfo.Refresh takes a snapshot of the file from the current
file system. Refresh cannot correct the underlying file system even if
the file system returns incorrect or outdated information. This can
happen on platforms such as Windows 98.
Calls must be made to Refresh before attempting to get the attribute
information, or the information will be outdated.
The key bits from MSDN indicate that it takes a snapshot and attribute information..will be outdated.
Try using FileInfo and Refresh method of it
fileInfo.Refresh();
var created = fileInfo.CreationTime;
this should work
File.Create(fullFilePathUri.LocalPath);
Thread.Sleep(1000); // give the file creation a chance to release any lock
That is not how you do it. File.Create creates stream writer which should be closed to release the lock without any waiting. If you find yourself using Thread.Sleep, you will often find that you are doing something wrong.
If the file described in the path parameter does not exist, this method returns 12:00 midnight, January 1, 1601 A.D. (C.E.) Coordinated Universal Time (UTC), adjusted to local time.
https://learn.microsoft.com/en-us/dotnet/api/system.io.file.getcreationtime?view=netframework-4.8

Delete files older than a date

I am currently working on a c# program where I check the creation time of a file and delete it if the file is older than 2 days. I have the following code snippet that should be achieving this.
DateTime creationTime = file.CreationTime.Date;
if (creationTime < DateTime.Now.AddDays(-logAge) && file.Name != currentLog)
{
File.Delete(string.Format("{0}/{1}", directory, file));
}
While my program is running it is constantly creating new files and a separate thread checks that the files are no older than say 2 days. If I have my PC's date set to the 24th April the files are created and kept as expected, if I then change the PC's date to the 25th April I would expect the files to remain as they are not older than 2 days, however, this is not the case as they are being deleted.
Log age is set to so I wouldn't have expected files to be deleted until after I had changed the date to be the 26th April.
What am I doing wrong, I've looked at many examples including another question on Stackoverflow Delete files older than 3 months old in a directory using .NET but its not doing what I would expect it to.
You forced to consider only the date part of the creation time-stamp then condition is satisfied and file will be deleted (earlier) anyway I suggest a few modifications to that code:
static class Helpers {
public static void DeleteOldFiles(string folderPath, uint maximumAgeInDays,
params string[] filesToExclude) {
DateTime minimumDate = DateTime.Now.AddDays(-maximumAgeInDays);
var filesToDelete = Directory.EnumerateFiles(folderPath)
.Where(x => !IsExcluded(x, filesToExclude));
foreach (var eligibleFileToDelete in filesToDelete)
DeleteFileIfOlderThan(eligibleFileToDelete, minimumDate);
}
private const int RetriesOnError = 3;
private const int DelayOnRetry = 1000;
private static bool IsExcluded(string item, string[] exclusions) {
return exclusions.Contains(item, StringComparer.CurrentCultureIgnoreCase);
}
private static void DeleteFileIfOlderThan(string path, DateTime date)
{
for (int i = 0; i < RetriesOnError; ++i) {
try {
var file = new FileInfo(path);
if (file.CreationTime < date)
file.Delete();
}
catch (IOException) {
System.Threading.Thread.Sleep(DelayOnRetry);
}
catch (UnauthorizedAccessException) {
System.Threading.Thread.Sleep(DelayOnRetry);
}
}
}
}
Notes
I'm still using DateTime.Now, I guess for this kind of operations you do not need any precision measurement (and you're talking about days so your thread may have a scheduled time of hours).
If your application uses multiple log files you can specify them all as parameters and they'll be ignored.
If you call DeleteOldFiles with 0 for maximumAgeInDays then you'll delay all log files not in use (as specified in the exclusion list).
Sometimes files can be in use (even if this should happen seldom in your case). The DeleteFileIfOlderThan function will retry to delete them after a short delay (it mimics Explorer.exe behavior).
You can call this function in this way:
Helpers.DeleteOldFiles(#"c:\mypath\", logAge, currentLog);
Few more notes:
This code doesn't combine path and file name but if you have to do it you should use Path.Combine(), I guess you do not want to reinvent the wheel each time to check if a path ends with a trailing backslash or not.
I/O operations can fail! Always check for exceptions.
file.Delete does make more sense than File.Delete(path) and Path.Combine() makes a lot more sense than using string.Format.
I've stumbled across this answer, don't know why I didn't find it before hand after spending ages on google, but this appears to have fixed the problem. DateTime.Compare how to check if a date is less than 30 days old?. The other problem was that I was using the file creation time but for my scenario it made more sense to use lastWriteTime.date.
I guess an additional problem must be in
File.Delete(string.Format("{0}/{1}", directory, file));
Your file is of type FileSystemInfo. Maybe you wanted to use file.Name.
Example: let's say directory is "c:\" and file points to "c:\myfile.log", your code will try to delete "c:/c:\myfile.log". It's hard for me to guess what exactly you have in these variables.
Correct replacement is suggested by #HenkHolterman:
file.Delete();

GetLastWriteTime returning 12/31/1600 7:00:00 PM

I am using the following code to write the Date Modified time of a Directory to a label
string selectedPath = comboBox1.SelectedItem.ToString();
DateTime lastdate = Directory.GetLastWriteTime(selectedPath);
datemodified.Text = lastdate.ToString();
It returns the date 12/31/1600 7:00:00 PM which I have no clue where it is getting that date from. Can anyone help me understand why it is returning that date and how I can fix it? I'm using .NET 3.5
From the documentation:
If the directory described in the path parameter does not exist, this method returns 12:00 midnight, January 1, 1601 A.D. (C.E.) Coordinated Universal Time (UTC), adjusted to local time.
So presumably your time zone is UTC-5 (in January), and the directory doesn't exist...
first thought is that of is your time set correctly. Second thought is to right click on that folder and see what it says in properties. Lastly I'd make new test folder and run that bit of GetLastWriteTime tests on it so you know what you are getting back.
GetLastWriteTime not always return reliable date time, use this
string selectedPath = comboBox1.SelectedItem.ToString();
DateTime now = DateTime.Now;
TimeSpan localOffset = now - now.ToUniversalTime();
DateTime lastdate = File.GetLastWriteTimeUtc(selectedPath) + localOffset;
datemodified.Text = lastdate.ToString();
Old question, but today I faced this issue. That particular date is also returned when your path is invalid or the file doesn't exists, because there is no built in exception in any of those cases.
An easy way to test for file not found with the result of GetLastWriteTime()/GetLastWriteTimeUtc() without hardcoding the sentinel epoch date/times that are used to indicate a file/dir not found condition, is as follows:
// ##### Local file time version #####
DateTime fileTimeEpochLocal=DateTime.FromFileTime(0);
// Use File.GetLastWriteTime(pathname) for files
// and Directory.GetLastWriteTime(pathname) for directories
DateTime lastWriteTime=Directory.GetLastWriteTime(selectedPath);
// Check for a valid last write time
if (lastWriteTime!=fileTimeEpochLocal) // File found
DoSomethingWith(selectedPath,lastWriteTime);
else // File not found
HandleFileNotFound(selectedPath);
// ##### UTC file time version #####
DateTime fileTimeEpochUtc=DateTime.FromFileTimeUtc(0);
// Use File.GetLastWriteTimeUtc(pathname) for files
// and Directory.GetLastWriteTimeUtc(pathname) for directories
DateTime lastWriteTimeUtc=Directory.GetLastWriteTimeUtc(selectedPath);
// Check for a valid last write time
if (lastWriteTimeUtc!=fileTimeEpochUtc) // File found
DoSomethingWith(selectedPath,lastWriteTimeUtc);
else // File not found
HandleFileNotFound(selectedPath);
In .net core, you will need to get the absolute path of the file.
Add reference to Microsoft.Extensions.Hosting and inject that into your constructor.
The ContentRootPath property will be your web root.
Grab your server path
var Files = FIO.Directory.GetFiles("Unzipped");
This will be your actual path
var Path = string.Format(#"{0}\{1}",WebRootPath, Files[0]);
var CreationDate = File.GetLastWriteTime(Path);

C# P/Invoke Attribute

New to C# Compact edition 6.5. I am trying to set the datetime on a file which seems to be off by 5 hours from the actual system time. I am doing only this to create the file:
FileStream fs= File.Create(name);
Just doing this the Created date is 5 hours ahead...if I try and set the CreationTime I get a compile error saying the Attribute is Readonly, seriously?
FileInfo fi = new FileInfo(name);
fi.CreationTime = date;
So my question is since I am new to C# how do you get access to a "readonly" Attribute in the CE framework? I see mentioning of P/Invoke but seems to work on methods only and not attributes. Anyone can given a quick demo on how to do this?
I've tried this solution and still get the file writing UTC even though I send it the current local time
I just ran this:
[MTAThread]
static void Main()
{
var name = "\\foo.txt";
var info = new FileInfo(name);
using (info.Create()) { }
info.Refresh();
var createTime = info.CreationTime;
var now = DateTime.Now;
var delta = now - createTime;
Debug.WriteLine(delta.ToString());
}
And got this output:
00:00:00.0140000
Which seems to be correct to me.
You can't modify the CreationTime of a file. It's set once and only once when the file is created. If you're willing to use P/Invoke to set the time, you can check out this similar question - c# - Change file LastWriteDate in Compact Framework
Instead of hacking the problem, though, you should fix the root cause. If there's an issue with the creation time of the file, I would consider checking your system's time settings (including timezone).

Categories