'Change date values and retain format
I want to replace a repeating year of dates in a column.
I started with a nested for loop in a single module, then I changed the code to be used for each sheet in it's relative module.
I tried replacing the repeating year with nothing and then adding the right year but it hangs at the middle.
Sub change_dates()
Dim wb As Workbook
Dim o As Long
Dim k As Long
Dim y As Long
Set wb = ThisWorkbook
y = Year(Date)
o = 2
k = wb.Worksheets(11).Cells(2, 10).Value + 2
Do While o < k
If Mid(wb.Worksheets(11).Cells(o, 1), 4, 2) = 12 Then
y = y - 1
End If
wb.Worksheets(11).Cells(o, 1) = Left(wb.Worksheets(11).Cells(o, 1), 6) & CStr(y)
o = o + 1
Loop
End Sub
The cell values after I run the code:
... 14/03/2014 14/02/2014 14/01/2014 13/12/2013 13/11/2013 13/10/2013 13/09/2013 13/08/2013 13/07/2013 13/06/2013 13/05/2013 13/04/2013 13/03/2013 13/02/2013 13/01/2013 12-12-2012 11-12-2012 10-12-2012 09-12-2012 08-12-2012 07-12-2012 06-12-2012 05-12-2012 04-12-2012 03-12-2012 02-12-2012 01-12-2012 12-11-2011 11-11-2011 ...
The first part is how I want it. In the second part the month is changing and the formatting too.
The original values of the column.
... 22-01-2022 21-12-2022 21-11-2022 21-10-2022 21-09-2022 21-08-2022 21-07-2022 21-06-2022 21-05-2022 21-04-2022 21-03-2022 21-02-2022 21-01-2022 20-12-2022 20-11-2022 20-10-2022 20-09-2022 20-08-2022 20-07-2022 20-06-2022 ...
This is the desired result:
22-01-2022 21-12-2021 21-11-2021 21-10-2021 21-09-2021 21-08-2021 21-07-2021 21-06-2021 21-05-2021 21-04-2021 21-03-2021 21-02-2021 21-01-2021 20-12-2020 20-11-2020 20-10-2020 20-09-2020 20-08-2020 20-07-2020 ...
Further clarifications:
- I get date as a result of =A2+1.
- The A column cells are all formatted dd-mm-yyyy
- k is returning the right number.
- The result should be, all the days and months remaining the same, and the repeating year 2022 changed to a year that starts in 2022 and decreases by one starting from the top down every time it's December.
Solution 1:[1]
The issue is if you use text/string functions like Mid()
or Left()
you change from a real numeric date (you can actually calculate with) to a text that only looks like a date but is just text (you cannot calculate with that anymore). And Excel does not know that this is a date.
So whenever working with dates use numeric date functions like Day()
, Month()
and Year()
to split the date into parts and use DateSerial(y, m, d)
to put a new date together. This will create a real numeric date you can calculate with, and that you can format with .NumberFormat
.
I changed your Do
loop into a For
loop that auto increments o
on Next o
, this looks a bit cleaner.
Public Sub change_dates()
Dim ws As Worksheet ' define your worksheet only once
Set ws = ThisWorkbook.Worksheets(11) ' if it ever changes from 11 to 12 it only needs to be changed here
Dim y As Long
y = Year(Date)
Dim k As Long
k = ws.Cells(2, 10).Value + 1
Dim o As Long
For o = 2 To k ' loop from 2 to k
Dim m As Long ' get month of current cell
m = Month(ws.Cells(o, 1))
Dim d As Long ' get day of current cell
d = Day(ws.Cells(o, 1))
If m = 12 Then ' check if year needs to change
y = y - 1
End If
ws.Cells(o, 1) = DateSerial(y, m, d) ' create a real numeric date and write it to the cell
' if the date needs to show in another format just change the numberformat to whatever you need
'ws.Cells(o, 1).NumberFormat = "dd-mm-yyyy"
Next o
End Sub
Solution 2:[2]
Manipulate Dates in Column
Option Explicit
Sub change_dates()
Const wsID As Variant = 11 ' e.g. "Sheet11" is a little more reliable
Const fRow As Long = 2
Const Col As String = "A"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Reference the column range ('rg').
Dim ws As Worksheet: Set ws = wb.Worksheets(wsID)
Dim lRow As Long: lRow = ws.Cells(ws.Rows.Count, Col).End(xlUp).Row
If lRow < fRow Then Exit Sub ' no data
Dim rg As Range: Set rg = ws.Range(ws.Cells(fRow, Col), ws.Cells(lRow, Col))
Dim cCell As Range
Dim cValue As Variant
Dim y As Long, m As Long, d As Long
Dim FirstDone As Boolean
' Read and write.
For Each cCell In rg.Cells
cValue = cCell.Value
If IsDate(cValue) Then
If FirstDone Then
d = Day(cValue)
m = m - 1
If m = 0 Then
m = 12
y = y - 1
End If
cCell.Value = DateSerial(y, m, d)
Else ' first date stays as is
y = Year(cValue)
m = Month(cValue)
FirstDone = True
End If
End If
Next cCell
End Sub
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | VBasic2008 |