Comparing dates to set font of text in Excel - excel

I am taking my open tasks from Outlook tasks and putting them into a spreadsheet.
I want to make any late tasks red and bold. This code works except that it also set three lines red, bold that are not late.
Because the ones that are incorrect are in the same month as current date, I am guessing that I have a data type mismatch, or something like that.
I tried using CDate, and that did not work either.
y = 2
For x = 1 To tasks.Count
Set tsk = tasks.Item(x)
'Fill in Data
If Not tsk.Complete Then
exWb.Sheets("Sheet1").Cells(y, 1) = tsk.DueDate
exWb.Sheets("Sheet1").Cells(y, 2) = tsk.Subject
If tsk.DueDate < Date Then
MsgBox tsk.DueDate & " " & Date
'Make red bold
exWb.Sheets("Sheet1").Cells(y, 1).Font.Bold = True
exWb.Sheets("Sheet1").Cells(y, 1).Font.Color = RGB(255, 0, 0)
End If
exWb.Sheets("Sheet1").Cells(y, 3) = tsk.PercentComplete
exWb.Sheets("Sheet1").Cells(y, 4) = tsk.Status
y = y + 1
End If
Next x
enter image description here

In Outlook evaluates date-time values according to the time format, short date format, and long date format settings in the Regional and Language Options applet in the Windows Control Panel. In particular, Outlook evaluates time according to that specified time format without seconds. If you specify seconds in the date-time comparison string, the filter will not operate as expected.
To make sure that the date-time comparison string is formatted as Microsoft Outlook expects, use the Visual Basic for Applications Format function (or its equivalent in your programming language). The following example creates a Jet filter to find all contacts that have been modified before June 12, 2022 at 3:30 P.M local time.
Format("6/12/2022 3:30PM","General Date")
When you are sure that both operands are dates, less or greater should work correctly. Otherwise, you can format dates and use the DateDiff function which returns a long specifying the number of time intervals between two specified dates.
Also, instead of iterating over all items in the tasks folder in Outlook and checking whether a particular task is completed:
For x = 1 To tasks.Count
Set tsk = tasks.Item(x)
'Fill in Data
If Not tsk.Complete Then
You need to use the Find/FindNext or Restrict methods of the Items class. They allow getting items that correspond to the specified criteria. You may read more about these methods in the article that I wrote for the technical blog:
How To: Use Outlook Find and FindNext methods to retrieve Task items
How To: Use Restrict method to retrieve Outlook Task items

Related

Can you assign index values to .Currentpage VBA/Excel?

I'm trying to create a Macro that will, among other things, set the .CurrentPage to a specific value. My question is can you use an index value instead of the name of one of the values?
ActiveSheet.PivotTables("PivotTable1").PivotFields("starttime").CurrentPage = "11/19/2018"
Here is an example line that I'm using. The problem is the dates will change every week to represent the new data. However there will always be five options, Monday to Friday. So instead of having to use the date, which I'll have to change every week, can I use an index value instead?
I.e. [0] for Monday and [4] for Friday etc. If this is possible then what is the correct syntax for this? I've looked all over the web and found nothing even remotely related to using index numbers instead of values.
If you know that your field will only contain the relevant items and nothing else, then:
With ActiveSheet.PivotTables("PivotTable1").PivotFields("starttime")
.CurrentPage = .PivotItems(3).Value
End With
However pivot tables may retain items deleted from the data source. If that is how it is set up for you, then you will either need to remove cached items before using this code, or calculate that page value instead of looking it up in the list of available values, which should be not difficult given that it is based on the current week.
Something like this
Public arrDate(4) As Date
Sub CreateDateArray()
Dim i As Integer
For i = 0 To 4
arrDate(i) = DateAdd("d", -Weekday(Date, vbMonday) + (i + 1), Date)
Next i
End Sub
or something like this
Function DateFromIndex(intDay As Integer) As Date
DateFromIndex = DateAdd("d", -Weekday(Date, vbMonday) + (intDay+1), Date)
End Function

Global VBA date format and decimal separator

Is there a way to change VBA settings globally on PC to accept dates and number on a specified format? (on my case dd/mm/yyyy and comma)
Changing Excel settings doesn't solve it for me.
As an small time VBA developer, I'm mostly creating userforms for data input and validation. Alongside with some basic access privileges, It keeps users (mostly an client's hired arms) from nosing on the database and corrupting it.
But, on form's submitting, the textbox values are saved temporally on spreadsheet's cells. Somehow on this step dates get scrambled and in some cases an 3 decimal places numeric gets multiplied by a thousand (e.g. 1/2/2000 turn to 2/1/2000 and 1,234 turn 1234). It defeats the whole purpose of those applications - data gets corrupted.
I've been able to workaround these using the Format(expression, format) function, but that must be applied every time an date or some precision number is added, or even used on some auxiliary task.
This is an recurrent problem for me because, as an Brazilian, dates are formatted as dd/mm/yyyy and decimal separator is ","(comma) on practically 100% of my local users.
Anybody had similar problems?
TIA
Excel doesn't have a default date format. Excel uses the Window System Date format settings. You can change you system setting by go to Control Panel -> Change date, time and number formats.
Change Date Format in Windows 7, 8.1 and Windows 10 to dd-mm-yyyy
After adjusting the Windows System Settings to dd-mm-yyyy, CDate will expect strings to be in the dd-mm-yyyy.
Range("A1").Value = CDate( "11/01/2016" )
Result: Monday, January 11, 2016
Summary of comments for those to lazy to read.
Alright, as Thomas Inzina pointed, the strait answer to my question is NO, you can't because there isn't such thing in VBA as this Global setting.
As Rory pointed out, the CDate function should solve (indeed it does) this issue, at least as to the date. Again, Thomas answer didn't include it but it points to the windows conf that would be used by the CDate function.
Datetimepicker, suggested by cyboashu, would solve this issue too, but it requires some tweaking on the user's PC to be available. Too much work for me. Although, this approach has the "pretty" advantage, adds value to your project.
Still looking for the comma/dot bad conversion problem. I'll keep editing this answer while none better exists.
Here I write a function called gdate that accepts a string with a date in a specific format. Then I parse the string, then call cdate based on the users date settings.
All I have to do is find/replace cdate with gdate throughout my code. Now I have a way to handle all date formats by always expecting an exact one gdate("mm/dd/yyyy"). Adjust the parsing if you want to expect different format. Building off built-in objects and functions is how we make things work.
Function gdate(ByVal dstring As String)
' 0 = month-day-year; 1 = day-month-year; 2 = year-month-day
d = Mid(dstring, InStr(1, dstring, "/") + 1, Len(dstring) - 5 - InStr(1, dstring, "/"))
m = Left(dstring, InStr(1, dstring, "/") - 1)
y = Right(dstring, 4)
dtype = Application.International(xlDateOrder)
Select Case dtype
Case 0: gdate = CDate(m & "/" & d & "/" & y)
Case 1: gdate = CDate(d & "/" & m & "/" & y)
Case 2: gdate = CDate(y & "/" & m & "/" & d)
End Select
End Function

Lotus Notes: Displaying days of a month, following the weekdays of it

I have a not so nice question. I've been thinking about this for like a month now and read a couple of books but can seem to find an answer or how to execute this. As you all know, I'm making this application that generates date. I have one combobox it has months in it, starting january to december, two column table, first colum displays the day and the second one displays the weekdays, on selecting month combobox, it must display the days in that month on first column and weekdays on 2nd column, by row. example: I choose january, on the first column it will display the days of that month, 1st row is 1, 2nd row is 2, and so on, and same as weekdays. I'm kinda new to LN. Can you give me an idea for it? Hope you can help me out.
This is a solution based on Notes #Formula. Only a few lines of code are necessary to achieve the result.
First we need the form
The formula for Days is
_days :=1:2:3:4:5:6:7:8:9:10:11:12:13:14:15:16:17:18:19:20:21:22:23:24:25:26:27:28:29:30:31;
_numberDays := #Day(#Adjust(#Adjust(#Date(#ToNumber(Year); #ToNumber(Month); 1); 0; 1; 0; 0; 0; 0); 0; 0; -1; 0; 0; 0));
#Subset(_days; _numberDays)
and the formula for Weekday is
_weekdays := #Transform( #ToNumber(Days); "day";
#Weekday(#Date(#ToNumber(Year); #ToNumber(Month); day)));
#Replace(#Text(_weekdays);
"1":"2":"3":"4":"5":"6":"7";
"Sunday":"Monday":"Tuesday":"Wednesday":"Thursday":"Friday":"Saturday")
That's it.
The fields Month and Year have to have the property "Refresh fields on keyword change".
The fields Days and Weekday need "Computed for display", "Allow multiple values" and "New Line" as separate values.
The result will look like this
Truly dynamic tables are difficult. In this case it's definitely possible because you have a defined number of rows, but it's still somewhat messy.
I'm not aware of anything built in that will easily tell you how many days there are in each month. I'd probably just create a config doc with year, month, and numberOfDays fields, and hidden view that you can use for lookups. You're going to need this in many places, and you don't want to do the lookup each time, so do it in a hidden computed field that comes after your dropdown but before your table. (Be sure to set properties so the field is recomputed after the value in the dropdown is changed.) Call the field something like daysInSelectedMonth.
Obviously the first column is easy: just create your table and enter the numbers 1 through 31, and apply a hide-when formula to the cells for rows 29 through 31 so that they only show up if daysInSelectedMonth is the right number of days. You don't need the hide when in the other rows.
For the second column, you will need to use computed for display fields. I would strongly suggest naming them something like weekday_1, weekday_2,... weekday_31 so that you can use #ThisName and some simple string manipulation to extract the number from the field name. That will tell you what row the formula is in, and it is your day number. The benefit of doing it this way is that your formula can be exactly the same in every one of the fields -- just a cut-and-paste into the other fields after you get it right once.
I would suggest starting to work on the formula in the weekday_31 field, and when you get it right (showing the correct weekday in a month that does have 31 days, and blank in a month that does not), then you can copy the formula to the rest of the fields. You will need to use an #If to detect whether the month has the correct number of days -- this is easy, except for leap year. I'm going to leave that part up to you. Just make it return "" if the month does not have the right number of days, and then have the final clause of the #f use #Date to build the value for the date that you are working on and then use the #Weekday function to display the value.
It all depends on a few things:
Web application or Notes client application?
What is the end result of the exercise, i.e. what is the table intended to be used for? Display purposes only?
Making some assumptions (Notes client application, and table used only for display), I see two ways to do this.
An easy way to do this is to create the table with 31 rows and 2 columns.
In the cells you create fields: Day1, Weekday1, Day2, Weekday2, etc.
You also need a year field, unless it is always current year.
Set a hide-when formula on rows 29-31, to hide if the Day field for that row is blank.
On the advanced properties tab for the combobox where you select month, set "Run Exiting/OnChange events after value change".
In the Exiting event for the combobox, write some Lotusscript that populate the fields with days and weekdays, based on selected year and month. Something like this (untested:
Sub Exiting(Source As Field)
Dim session As New NotesSession
Dim ws As New NotesUIWorkspace
Dim uidoc As NotesUIDocument
Dim monthName As String
Dim YYYY As String
Dim firstDate As NotesDateTime
Dim lastDate As NotesDateTime
Dim n As Double
Dim i As Integer
Dim dayname(1 To 7) As String
dayname(1) = "Sunday"
dayname(2) = "Monday"
dayname(3) = "Tuesday"
dayname(4) = "Wednesday"
dayname(5) = "Thursday"
dayname(6) = "Friday"
dayname(7) = "Saturday"
Set uidoc = ws.CurrentDocument
YYYY = uidoc.FieldGetText("Year")
monthName = uidoc.FieldGetText("Month")
Set firstDate = New NotesDateTime("1 " & monthName & ", " & YYYY)
Set lastDate = New NotesDateTime(firstDate.DateOnly)
Call lastDate.AdjustMonth(1)
Call lastDate.AdjustDay(-1)
i = 0
For n = Cdbl(firstDate.LSLocalTime) To Cdbl(lastDate.LSLocalTime)
i = i + 1
Call uidoc.FieldSetText("Day" & i, Cstr(i))
Call uidoc.FieldSetText("Weekday" & i, dayname(Weekday(Cdat(n))))
Next
Call uidoc.Refresh()
End Sub
Another way to create a truly dynamic table, is the method I blogged about here:
http://blog.texasswede.com/dynamic-tables-in-classic-notes/
The benefit is that it is more flexible, and you can create a nicer layout without needing to create a large number of fields.

Dates and Charting

I have three sets of data and each has two columns.
The first column is Date and second column is Price. The dates are formatted different with each data set eg. Gold's date(1951), Money Supply M2's date (1951-01), and Money Sup. M3 Date (9/01/1951)
What i need:
I want to chart these with dates on x-axis and price on y-axis
Questions:
do i need to make Gold's Date(YYYY) and Money Supply M2's Date(YYYY-MM) a date object?
if so how?
do i need to place all dates in one column and create a sub to help sort the Price with appropriate Date?
Does this make sense?
I have very little experience programming in VBA and was having a hard time finding info on using dates. I came across an Answer, given by the person who edited this (brettdj), that listed a few extremely helpful sights on VBA programming for excel. One of those had info on the DateSerial() function. I was then able to throw together some code to quickly fix my problem.
Sub CreateDates()
Dim dt As Date
Dim s As String
For Each c In Worksheets("Sheet1").Range("A7:A27080").Cells
s = Len(c.Value)
If s = 4 Then '(YYYY)
dt = DateSerial(s, 7, 1)
c.Value = dt
End If
If s = 7 Then '(YYYY-MM)
y = Left(s, 4)
m = Right(s, 2)
dt = DateSerial(y, m, 1)
c.Value = dt
End If
Next c
End Sub
I could probably spend some time and add some regular expressions and make a one-size fits most, but this will work as i want have to use it very often.

Removing tags from formatted text in Excel cells

Walk with me for a moment.
I have built an Access application to manage data for an internal project at my company. One of the functions of this application is queries the database, then outputs the queries to an Excel spreadsheet, then formats the spreadsheet to spec.
One of the cells of the output is a large amount of text from a Rich Text Memo field in the database. When the rich text is sent to Excel it carries with it HTML tags indicating bold or italic, so for the output I have to add the formatting and remove the tags.
Here is an example of the text I need to format (this text is in a single cell):
For each participant, record 1 effort per lesson delivered
• Time Spent = # minutes spent on lesson
<strong>OR</strong>
For each participant, record 1 effort per month
• Time Spent = total # minutes spent on lessons that month
<strong>Note:</strong> Recording 1 effort per lesson is recommended but not required
<strong>Note:</strong> Use groups function in ABC when appropriate (see <u>Working With Groups</u> in ABC document library on the ABC portal)
I have a three neat little recursive functions for formatting the text, here is the bolding function:
Function BoldCharacters(rng As Range, Optional ByVal chrStart As Long)
'This will find all the "<strong></strong>" tags and bold the text in between.
Dim tagL As Integer
tagL = 8
rng.Select
If chrStart = 0 Then chrStart = 1
b1 = InStr(chrStart, ActiveCell.Value, "<strong>") + tagL
If b1 = tagL Then Exit Function
b2 = InStr(b1, ActiveCell.Value, "</strong>")
ActiveCell.Characters(Start:=b1, Length:=b2 - b1).Font.Bold = True
'Remove the tags
'ActiveCell.Characters(Start:=1, Length:=1).Delete
'ActiveCell.Characters(Start:=b2 - tagL, Length:=tagL + 1).Delete
'Recursion to get all the bolding done in the cell
Call BoldCharacters(ActiveCell, b2 + tagL + 1)
End Function
Now here's the issue. This formats the text nicely. But the "ActiveCell.Characters.Delete" method fails when I attempt to use it to remove the tags because the cell contains more than 255 characters. So I can't use the delete method.
And when I do this:
With xlApp.Selection
.Replace what:="<strong>", replacement:=""
The tags are all removed, but the formatting is all destroyed! So what's the point!?
I'm looking for a way of formatting my text and removing the tags. I'm considering taking the large bit of text and 'chunking' it up into a number of cells, processing the formatting and re-assembling, but that sounds difficult, prone to error, and might not even work.
Any ideas!?
Thanks!
You might want to remove the formatting before exporting the data to Excel. At the same time that you remove the formatting, store the formatting information (location, length, style) to a data structure. After you export the "plain text" data you could then iterate over your structure and apply the formatting in Excel. This could be a time consuming process depending upon how many records you plan on exporting at a given time, but it would remove the limitation imposed by Excel.
If it's well formed html (ie it always has closing tags) then you could use a regular expression.
Dim data As String
data = "For each participant, record 1 effort per lesson delivered • Time Spent = # minutes spent on lesson <strong>OR</strong> For each participant, record 1 effort per month • Time Spent = total # minutes spent on lessons that month <strong>Note:</strong> Recording 1 effort per lesson is recommended but not required <strong>Note:</strong> Use groups function in ABC when appropriate (see <u>Working With Groups</u> in ABC document library on the ABC portal)"
Dim r As New RegExp
r.Pattern = "<(.|\n)*?>"
r.Global = True
Debug.Print r.Replace(data, "")
To use the RegExp object, set a reference to Microsoft VBScript Regular Expressions 5.5.
hth
Ben
Something along these lines might be useful:
Sub DoFormat(rng As Range)
Dim DataObj As New MSForms.DataObject
Dim s As String, c As Range
For Each c In rng.Cells
s = "<html>" & Replace(c.Value, " ", " ") & "</html>"
DataObj.SetText s
DataObj.PutInClipboard
c.Parent.Paste Destination:=c
Next c
End Sub
You'll need a reference to "Microsoft Forms 2.0 Object Library"

Resources