Awk Sort by Today's date (not alphabetical) - awk

I have the following lines in a file. The first columns look like this (these are dates and time):
May 29 23:14:39
Dec 20 19:45:15
Nov 3 13:15:19
Sep 8 10:34:15
Mar 9 18:39:20
Jan 17 19:34:59
I would like to use awk to sort it by today's date. For example today is November 03 (Nov 3). Tomorrow it will be November 04 (Nov 4). The dates will be there accordingly as the days change and the file changes along. Now I would like the first line to be the today's date all the time / always. Is that even possible to sort it out like this using either awk, sed and the like?
Alphabetical sort does not work because it does 1,2,3,4 and so on and if today is January 20 for example, my first line will be January 1 anyway (not January 20) because it will do alphabetical order / sort.
Would appreciate any help / suggestions / pointers. Many thanks in advance.
P.S. Let me edit this as asked by Cyrus.
Well, the following code actually works, but... sed '/reject/!d' file.txt | sort -r -k2'... It goes like this: November 1, November, 2, November 3, and then October 31. I guess it grabs numbers like so 1,2,3,31. If I could get it to solve this it would also work. Thanks.
My desired output is to sort it by date with the current today's date to be the first line in my file all the time. However, the code above would also work for me if I could get it to count November 1, November 2, November 3, November 4 (instead of November 1, November 2, November 3, October 31).
P.S.S. That's another edit as per Ed's Morton request.
The dates are all there. I do not need to add anything. The only requirement is for today's date line to be the first one in that file all the time and then sort it out backwards in descending order. For example today is November 05, 2022 and this is the first line in the file like this Nov 5 12:45:89. Then all the other lines are for November 4, 3, 2, 1. Then all the other lines are for October 31, 30, 29, 28 and so on. It is supposed to go backwards and it has to start from the current date, that is from "today" all the time. For example tomorrow the first line has to be Nov 6 and everything else backwards. Then the day after tomorrow the first line has to be Nov 7 and everything else backwards and so on and so forth. I do not need to truncate anything. I do not need to add anything. I do not need to delete anything. All the data has to stay there and go backwards starting from the "current" day, whether it is today, tomorrow, after tomorrow and so on. I hope it's clear enough. Thanks.

It sounds like this, using any POSIX compliant versions of the tools, might be what you want but without expected output in the question it's a guess:
$ cat tst.sh
#!/usr/bin/env bash
awk -v today="$(date +'%F')" '
BEGIN {
OFS = "\t"
split(today,d,/-/)
year = d[1]
}
{
mthNr = index(" JanFebMarAprMayJunJulAugSepOctNovDec",$1) / 3
date = sprintf("%04d-%02d-%02d", year, mthNr, $2)
}
date <= today {
print date, $3, $0
}
' "${#:--}" |
sort -rk1,2 |
cut -f3-
$ ./tst.sh file
Nov 3 13:15:19
Sep 8 10:34:15
May 29 23:14:39
Mar 9 18:39:20
Jan 17 19:34:59
The above uses a DSU approach to solve the problem. It's sorting on both date and time so for the same date the output is similarly ordered by the time that day.

Related

Getting current day number with awk and date

The output of date command has two spaces when the day number is less than 10. For example
Mon May 31 10:24:01 +0430 2020
Mon Jun 1 10:24:01 +0430 2020
For the first one, date | cut -d " " -f 3 returns 31. But, for the second one, it returns SPACE. Any way to fix that?
You could simple try awk to get the 3rd field, which will be definitely better than cut command.
date | awk '{print $3}'
Now why cut command is not working IMHO because space between May and 31 is equal but space between Jun and 1 is not equal so you need to use f4 in your cut command(for single digit date numbers with your current approach). Its better to use awk in this case.
Or In ideal scenario if you want to get only date then use date '+%d' to get date always in 2 digit as per #anubhava sir's comments.

Trying to format date to save worksheet

I am looking to save an individual worksheet from a workbook with today's date in the filename. ex. (c:\HotDogS\sales\Daily_12_04_16.xslx)
The problem I am encountering is getting the date to show right in the filename.
I have 1 cell that has the simple formula of =TODAY(). The cell is formatted for mm/dd/yy.
The formula I am trying to use to save the date for the sheet is:
=left(B3,2)&"_"&mid(B3,4,2)&"_"&right(B3,2)
So I am expecting a date of 12/04/16 to come out as 12_04_16, but I am getting is, 42_08_08.
Can somebody shed some light on this??
Thank you!!
Assuming TODAY is 4 December 2016, i.e. serial day number 42708, your formula is:
=left(B3,2)&"_"&mid(B3,4,2)&"_"&right(B3,2)
Left(B3,2) is 42. Mid(B3,4,2) is 08. Right(B3,2) is 08.
So your final result is 42_08_08.
You probably want to use (as an Excel formula):
=TEXT(B3,"mm\_dd\_yy")
Or in VBA you could use
Format(Range("B3").Value, "mm_dd_yy")
Excel stores dates as the number of days (and fractions of a day) since 0 January 1900. Therefore
1 January 1900 is day 1
31 January 1900 is day 31
1 February 1900 is day 32
29 February 1900 (even though it doesn't exist - but the bug has been maintained for backward compatibility) is day 60
1 January 1901 is day 367
4 December 2016 is day 42708
NOW() is day 42709.328 (it's about 7:52am on 5 December 2016 at the moment)
Referencing a cell formatted as date returns the underlying date serial number.
To get a date formatted as you want use
=TEXT(B3,"dd\_mm\_yy")

Lookup a value from a range of dates in excel

Please help.
We have two tables. A list of accounts and the other is a change log. I need to add a new column in table 1 where the value is the amount in table 2 for the correct account and correct validity period.
ex.
table 1:
account# beginning period ending period
1 January 1, 2012 January 31, 2012
2 January 12, 2012 February 12, 2012
table 2:
account # amount valid period beg valid period end
1 10 january 1, 2009 december 5, 2010
1 20 december 6, 2010 june 1, 2011
1 30 june 2, 2011 december 1, 2012
2 13 january 15, 2011 december 15, 2011
2 20 december 16, 2011 february 20, 2012
Thanks.
Although it is a bit complex requirement it could be done with built-in functions (although it can look a bit obscure :-) ). Specifically I mean function SUMIFS.
It has several parameters.
The first one is an area with values to be summed. It is B8:B12 in this example.
The second is an area whith values to be checked with some condition. It is A8:A12.
The third is a criterion to be applied for area from second parameter. It is (inter alia) account #.
So the formula says: sum all values from rows in B8:B12 where account # (A8:A12) is equal to desired account # (e.g. A3).
Ok, it is not all, you need specify the time range. It would be a bit clunky because you must check if two time period are overlapping (it would be easier to check if one date is in specified period).
But it could be done because SUMIFS can take another pairs of criteria range and criterion. But it cannot be used for OR condition, so you had to combine more SUMIFS.
Nice article about overlapping ranges is e.g. http://chandoo.org/wp/2010/06/01/date-overlap-formulas/
BTW: you have to format cells in B2:C3 and C8:D12 as a date to be able to compare them.

Sorting records based on modified timestamp?

I am trying to sort a list of records that have been created using a screen scraping script. The script adds the following style of date and time (timestamp) to each record:
13 Jan 14:49
The script runs every 15 minutes, but if I set the sort order to 'time DESC' it doesn't really make sense because it lists the records as follows:
13 Jan 14:49
13 Jan 12:32
13 Jan 09:45
08 Feb 01:10
07 Feb 23:31
07 Feb 06:53
06 Feb 23:15
As you can see, it's listing the first figure correctly (the day of the month in number form) but it's putting February after January. To add to the confusion it's putting the latest date in February at the top of the February section.
Is there a better way of sorting these so they are in a more understandable order?
If you are storing the values in a database, simply use the column type datetime when creating the field. The database will treat the field as time and will sort the values chronologically.
Otherwise, if you are storing the values elsewhere, for example in a flat file, convert the formatted time to unix time. Unix time is an integer, thus you can sort it easier.
Time.parse("13 Jan 09:45").to_i
# => 1326444300
Time.parse("08 Feb 01:10").to_i
# => 1328659800
You can always convert a unix time to a Time instance.
Time.at(1328659800).to_s
# => "2012-02-08 01:10:00 +0100"

When was this clock bought?

The clock on the gym wall also shows the day name and the day of the month. This morning it showed Tuesday - 23.
The day obviously rotates through a cycle of 7 - and showed "Tuesday" correctly. The day of the month, though, presumably rotates through a cycle of 31 and showed "23" incorrectly - today is the 1st December (ie. not the 31st November). So this error has been slowly accruing over time.
Given the assumption that no-one has ever reset the clock, what's the most elegant, quick, optimised way of suggesting some of the possible dates for when this clock was bought brand new.
(Bonus credit for showing when the clock will again show the correct day/number combination.)
01-Oct-17 is when the clock will again show the correct day/number combination.
The day of the week (i.e. Tuesday, ... etc) will always be correct, so it is irrelevant to your problem.
Assuming non leap year, you can build a table of 12 rows (1 per month) containing the number of days in this month minus 31.
Jan 0
Feb -3
Mar 0
Apr -1
May 0
Jun -1
Jul 0
Aug 0
Sep -1
Oct 0
Nov -1
Dec 0
You can build a table of the displayed date for every 1st of the month, by adding to the day of the previous month the related number in this list. If the number is negative or equal to zero, add 31 to the figure.
i.e. from the 1st Dec 09 (date at which the clock is displaying 23), you can go to the 1st Jan 10.
You look at this table and find the figure next to Dec, it is 0.
Add 0 to 23 and you know that on the 1st Jan 10, the clock will be displaying 23.
From the 1st Jan 09, you know that the date which will be displayed on the 1st Feb 10 is 23.
From the 1st Feb 10, you can compute the value for the 01 Mar 10, it is 23 + (-3) = 20.
... etc
So, now, at every start of month where you get a value of 1 in this table, you know that the dates in this month will be correct.
If you have to include leap year, you need a second table with the values for a leap year or make an exception for February.
If you want to use this computation for previous dates, substract the figure from the table and when the number you obtain is over 31, just substract 31 to get the day number.
Using these tables and taking in account leap years.
The last past date at which the clock was correct was the 30 September 08 (it was correct between the 01-Jul-08 and the 30-Sep-08)
The next date at which it will be correct will be the: 01-Oct-17 and it will still be correct on the 30-Nov-17.
Now = 1 Dec 2009.
1st day of the month minus 23rd of past month = 8 days (assuming 31 day month).
Moving back counting non-31-days month...
Nov, Sep, June, Apr, Feb (X3), Nov = 8 days offset
So it was bought before Nov 2008?
I didn't code a single line for it, so pardon me if the answer is way off.
In Excel, you can test any date in A2 to see whether the clock will be correct on that date, with the formula =MOD(A2+19,31)+1=DAY(A2)