C++ - Inkrementera/addera månader till std::chrono::system_clock::time_point?

Permalänk
Medlem

C++ - Inkrementera/addera månader till std::chrono::system_clock::time_point?

Hej,

Jag håller på med ett litet program där jag behöver addera ett visst antal månader till en std::chrono::system_clock::time_point; jag har inte kommit på något bra sätt än själv. Min kompilator:

alexl@PD70PNP:~$ g++ --version g++ (Debian 12.2.0-14) 12.2.0 Copyright (C) 2022 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Det ledde mig till denna sida:
https://stackoverflow.com/questions/43010362/c-add-months-to-chronosystem-clocktime-point

Dock fungerar inte koden från sektionen "The Calendrical Computation" (visad nedan) för mig. Jag har korrigerat exemplet för C++20:

// Get the current time auto now = std::chrono::system_clock::now(); // Get a days-precision chrono::time_point auto sd = std::chrono::floor<days>(now); // Record the time of day auto time_of_day = now - sd; // Convert to a y/m/d calendar data structure std::chrono::year_month_day ymd = sd; // Add the months ymd += std::chrono::months{8}; // Add some policy for overflowing the day-of-month if desired if (!ymd.ok()) ymd = ymd.year()/ymd.month()/last; // Convert back to system_clock::time_point std::chrono::system_clock::time_point later = sys_days{ymd} + time_of_day;

Den framtida fungerande koden skall sättas in i en funktion som än så länge ser ut så här:

std::chrono::system_clock::time_point add_months(std::chrono::system_clock::time_point tp, int months) { //Function body. }

Jag vill komma fram till en funktion som kan inkrementera/addera månader så att t.ex.:

1901-01-01 + 1 månad = 1901-02-01 osv.

Jag hoppas jag gjort mig förstådd och undrar om någon kan hjälpa mig?

Permalänk
Medlem

Intressant! Jag har inte sysslat med detta i C++ tidigare, och nu när jag läser om det verkar det finnas en hel del olika sätt att representera tid i C++, och konvertering däremellan måste så klart göras. Jag lyckades få ihop denna koden dock, som är rätt så självförklarande.

#include <chrono> // chrono::system_clock #include <sstream> // stringstream #include <iomanip> // put_time #include <string> // string #include <iostream> void write_time(std::chrono::system_clock::time_point intime) { std::stringstream ss; time_t time = std::chrono::system_clock::to_time_t(intime); std::cout << std::put_time(std::localtime(&time), "%Y-%m-%d %X") << std::endl; } int main() { // Hämta aktuell tid std::chrono::system_clock::time_point time = std::chrono::system_clock::now(); // En variabel för ytterligare en tid, som vi sätter till samma std::chrono::system_clock::time_point later_time = time; // Lägg till en månad later_time += std::chrono::months{1}; // skriv ut tiderna. write_time(time); write_time(later_time); }

(Jag kompilerar med

g++ --std=c++20 test.cpp -o test

)

Permalänk
Medlem
Skrivet av gusnan:

Intressant! Jag har inte sysslat med detta i C++ tidigare, och nu när jag läser om det verkar det finnas en hel del olika sätt att representera tid i C++, och konvertering däremellan måste så klart göras. Jag lyckades få ihop denna koden dock, som är rätt så självförklarande.

#include <chrono> // chrono::system_clock #include <sstream> // stringstream #include <iomanip> // put_time #include <string> // string #include <iostream> void write_time(std::chrono::system_clock::time_point intime) { std::stringstream ss; time_t time = std::chrono::system_clock::to_time_t(intime); std::cout << std::put_time(std::localtime(&time), "%Y-%m-%d %X") << std::endl; } int main() { // Hämta aktuell tid std::chrono::system_clock::time_point time = std::chrono::system_clock::now(); // En variabel för ytterligare en tid, som vi sätter till samma std::chrono::system_clock::time_point later_time = time; // Lägg till en månad later_time += std::chrono::months{1}; // skriv ut tiderna. write_time(time); write_time(later_time); }

(Jag kompilerar med

g++ --std=c++20 test.cpp -o test

)

Intressant; testar nu.

Permalänk
Medlem
Skrivet av gusnan:

Intressant! Jag har inte sysslat med detta i C++ tidigare, och nu när jag läser om det verkar det finnas en hel del olika sätt att representera tid i C++, och konvertering däremellan måste så klart göras. Jag lyckades få ihop denna koden dock, som är rätt så självförklarande.

#include <chrono> // chrono::system_clock #include <sstream> // stringstream #include <iomanip> // put_time #include <string> // string #include <iostream> void write_time(std::chrono::system_clock::time_point intime) { std::stringstream ss; time_t time = std::chrono::system_clock::to_time_t(intime); std::cout << std::put_time(std::localtime(&time), "%Y-%m-%d %X") << std::endl; } int main() { // Hämta aktuell tid std::chrono::system_clock::time_point time = std::chrono::system_clock::now(); // En variabel för ytterligare en tid, som vi sätter till samma std::chrono::system_clock::time_point later_time = time; // Lägg till en månad later_time += std::chrono::months{1}; // skriv ut tiderna. write_time(time); write_time(later_time); }

(Jag kompilerar med

g++ --std=c++20 test.cpp -o test

)

Jag får detta fel i VS Code:

EDIT: Koden kompilerar dock; vilket är lite konstigt:

alexl@PD70PNP:/mnt/Storage_SSD/C++_Projects/sunday_count$ make g++ -std=c++20 -Wall -o obj/functions.o -c src/functions.cpp src/functions.cpp: In function ‘std::chrono::_V2::system_clock::time_point func::add_months(std::chrono::_V2::system_clock::time_point, int)’: src/functions.cpp:51:5: warning: no return statement in function returning non-void [-Wreturn-type] 51 | } | ^ g++ -std=c++20 -Wall -o obj/main.o -c src/main.cpp g++ -std=c++20 -Wall -o sunday_count obj/functions.o obj/main.o alexl@PD70PNP:/mnt/Storage_SSD/C++_Projects/sunday_count$ ./sunday_count 2023-11-03 11:22:31 2023-12-03 21:51:37 alexl@PD70PNP:/mnt/Storage_SSD/C++_Projects/sunday_count$

Permalänk
Medlem
Skrivet av Apollo11:

Jag får detta fel i VS Code:

Kompilerar du med C++-20-standarden aktiverad? I g++ så kan man aktivera detta (vilket krävs för chrono::months) med hjälp av --std=c++20 som kommandoparameter. (Du kan se vilken kommandorad jag använder för att kompilera i mitt tidigare inlägg).

Permalänk
Medlem

Det ser enligt felmeddelandet ut som om write_time i din kod inte returnerar void.

Permalänk
Medlem
Skrivet av gusnan:

Kompilerar du med C++-20-standarden aktiverad? I g++ så kan man aktivera detta (vilket krävs för chrono::months) med hjälp av --std=c++20 som kommandoparameter. (Du kan se vilken kommandorad jag använder för att kompilera i mitt tidigare inlägg).

Min Makefile:

######################################################################## ####################### Makefile Template ############################## ######################################################################## # Compiler settings - Can be customized. CC = g++ CXXFLAGS = -std=c++20 -Wall LDFLAGS = # Makefile settings - Can be customized. APPNAME = sunday_count EXT = .cpp SRCDIR = src OBJDIR = obj ############## Do not change anything from here downwards! ############# SRC = $(wildcard $(SRCDIR)/*$(EXT)) OBJ = $(SRC:$(SRCDIR)/%$(EXT)=$(OBJDIR)/%.o) DEP = $(OBJ:$(OBJDIR)/%.o=%.d) # UNIX-based OS variables & settings RM = rm DELOBJ = $(OBJ) # Windows OS variables & settings DEL = del EXE = .exe WDELOBJ = $(SRC:$(SRCDIR)/%$(EXT)=$(OBJDIR)\\%.o) ######################################################################## ####################### Targets beginning here ######################### ######################################################################## all: $(APPNAME) # Builds the app $(APPNAME): $(OBJ) $(CC) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) # Creates the dependecy rules %.d: $(SRCDIR)/%$(EXT) @$(CPP) $(CFLAGS) $< -MM -MT $(@:%.d=$(OBJDIR)/%.o) >$@ # Includes all .h files -include $(DEP) # Building rule for .o files and its .c/.cpp in combination with all .h $(OBJDIR)/%.o: $(SRCDIR)/%$(EXT) $(CC) $(CXXFLAGS) -o $@ -c $< ################### Cleaning rules for Unix-based OS ################### # Cleans complete project .PHONY: clean clean: $(RM) $(DELOBJ) $(DEP) $(APPNAME) # Cleans only all files with the extension .d .PHONY: cleandep cleandep: $(RM) $(DEP) #################### Cleaning rules for Windows OS ##################### # Cleans complete project .PHONY: cleanw cleanw: $(DEL) $(WDELOBJ) $(DEP) $(APPNAME)$(EXE) # Cleans only all files with the extension .d .PHONY: cleandepw cleandepw: $(DEL) $(DEP)

Permalänk
Medlem

Ja, nu har du ju -std=c++-20, och den delen är ok - varningen gäller något annat. (Den är ganska självförklarande). Svårt att säga vad dock då jag inte vet hur din kod ser ut på raden som varningen gäller. Men varningen säger ganska tydligt vad felet är. (Om du inte returnerar något i en funktion kan du definiera den som void).

Permalänk
Medlem
Skrivet av gusnan:

Ja, nu har du ju -std=c++-20, och den delen är ok - varningen gäller något annat. (Den är ganska självförklarande). Svårt att säga vad dock då jag inte vet hur din kod ser ut på raden som varningen gäller. Men varningen säger ganska tydligt vad felet är. (Om du inte returnerar något i en funktion kan du definiera den som void).

Det är en funktion som ännu inte är klar; därav felet.

Permalänk
Medlem

Problemet är att VS Code självt inte verkar vara inställt på C++20, så den tror att koden är fel. När du faktiskt kompilerar så används dock --std=c++20 vilket gör att det fungerar (förutom varningen om att du inte returnerar något från funktionen). Men VS Code kan inte avgöra det från din Makefile, du måste ställa in det i C++-tillägget du använder i VS Code på något sätt.

Permalänk
Medlem
Skrivet av perost:

Problemet är att VS Code självt inte verkar vara inställt på C++20, så den tror att koden är fel. När du faktiskt kompilerar så används dock --std=c++20 vilket gör att det fungerar (förutom varningen om att du inte returnerar något från funktionen). Men VS Code kan inte avgöra det från din Makefile, du måste ställa in det i C++-tillägget du använder i VS Code på något sätt.

Ah! Det förklarar ju en del. Tack! (Har inte så bra koll på VS Code tydligen )

Permalänk
Medlem
Skrivet av gusnan:

Intressant! Jag har inte sysslat med detta i C++ tidigare, och nu när jag läser om det verkar det finnas en hel del olika sätt att representera tid i C++, och konvertering däremellan måste så klart göras. Jag lyckades få ihop denna koden dock, som är rätt så självförklarande.

#include <chrono> // chrono::system_clock #include <sstream> // stringstream #include <iomanip> // put_time #include <string> // string #include <iostream> void write_time(std::chrono::system_clock::time_point intime) { std::stringstream ss; time_t time = std::chrono::system_clock::to_time_t(intime); std::cout << std::put_time(std::localtime(&time), "%Y-%m-%d %X") << std::endl; } int main() { // Hämta aktuell tid std::chrono::system_clock::time_point time = std::chrono::system_clock::now(); // En variabel för ytterligare en tid, som vi sätter till samma std::chrono::system_clock::time_point later_time = time; // Lägg till en månad later_time += std::chrono::months{1}; // skriv ut tiderna. write_time(time); write_time(later_time); }

(Jag kompilerar med

g++ --std=c++20 test.cpp -o test

)

Hur kan jag anpassa write_time så att den returnerar en std::string med formateringen "%F %T"? Min kod hittills:

std::string write_time(std::chrono::system_clock::time_point intime) { std::stringstream ss; std::time_t time = std::chrono::system_clock::to_time_t(intime); return std::put_time(std::localtime(&time), "%F %T"); }

Jag behöver hjälp med det.

Permalänk
Medlem
Skrivet av Apollo11:

Hur kan jag anpassa write_time så att den returnerar en std::string med formateringen "%F %T"? Min kod hittills:

std::string write_time(std::chrono::system_clock::time_point intime) { std::stringstream ss; std::time_t time = std::chrono::system_clock::to_time_t(intime); return std::put_time(std::localtime(&time), "%F %T"); }

Jag behöver hjälp med det.

Du måste använda dig om stömmar, och sedan konvertera den till en vanlig sträng:

std::string write_time(std::chrono::system_clock::time_point intime) { std::stringstream ss; time_t time = std::chrono::system_clock::to_time_t(intime); ss << std::put_time(std::localtime(&time), "%F %T"); return ss.str(); }

Ändra till %F %T vilket efterfrågades.
Permalänk
Medlem
Skrivet av gusnan:

Du måste använda dig om stömmar, och sedan konvertera den till en vanlig sträng:

std::string write_time(std::chrono::system_clock::time_point intime) { std::stringstream ss; time_t time = std::chrono::system_clock::to_time_t(intime); ss << std::put_time(std::localtime(&time), "%F %T"); return ss.str(); }

Tack! Min kod nedan:
functions.cpp:

std::chrono::system_clock::time_point add_months(std::chrono::system_clock::time_point tp, int month_count) { // Get a days-precision chrono::time_point auto sd = std::chrono::floor<std::chrono::days>(tp); // Record the time of day auto time_of_day = tp - sd; // Convert to a y/m/d calendar data structure std::chrono::year_month_day ymd = sd; // Add the months ymd += std::chrono::months{month_count}; // Add some policy for overflowing the day-of-month if desired if (!ymd.ok()) ymd = ymd.year()/ymd.month()/std::chrono::last; // Convert back to system_clock::time_point std::chrono::system_clock::time_point later = std::chrono::sys_days{ymd} + time_of_day; return later; } std::string write_time(std::chrono::system_clock::time_point intime) { std::stringstream ss; std::time_t time = std::chrono::system_clock::to_time_t(intime); ss << std::put_time(std::localtime(&time), "%F %T"); return ss.str(); }

och main.cpp:

int main() { //Setting start date for search. std::tm tm_start_date = {}; std::stringstream start_date_str_stream("1901-01-01"); start_date_str_stream >> std::get_time(&tm_start_date, "%Y-%m-%d"); auto start_date_tp = std::chrono::system_clock::from_time_t(std::mktime(&tm_start_date)); std::cout << func::write_time(start_date_tp) << '\n'; //std::cout << func::write_time(func::add_months(start_date_tp, 1)) << '\n'; for (int m = 1; m <= 12; m++) { std::cout << func::write_time(func::add_months(start_date_tp, m)) << '\n'; } return 0; }

Detta ger:

alexl@PD70PNP:/mnt/Storage_SSD/C++_Projects/sunday_count$ make g++ -std=c++20 -Wall -o obj/main.o -c src/main.cpp g++ -std=c++20 -Wall -o sunday_count obj/functions.o obj/main.o alexl@PD70PNP:/mnt/Storage_SSD/C++_Projects/sunday_count$ ./sunday_count 1901-01-01 00:00:00 1901-02-01 00:00:00 1901-03-01 00:00:00 1901-04-01 00:00:00 1901-05-01 00:00:00 1901-06-01 00:00:00 1901-07-01 00:00:00 1901-08-01 00:00:00 1901-09-01 00:00:00 1901-10-01 00:00:00 1901-11-01 00:00:00 1901-12-01 00:00:00 1902-01-01 00:00:00 alexl@PD70PNP:/mnt/Storage_SSD/C++_Projects/sunday_count$

Jag har även satt VS Code:s C++-standard till C++20 nu:

Permalänk
Medlem

Som en liten övning, fundera på vad som händer om du sätter start-datum till 2023-01-31 och sedan lägger till en månad. Vilket datum får du, och vilket borde du få?

Permalänk
Medlem
Skrivet av Erik_T:

Som en liten övning, fundera på vad som händer om du sätter start-datum till 2023-01-31 och sedan lägger till en månad. Vilket datum får du, och vilket borde du få?

int main() { //Setting start date for search. std::tm tm_start_date = {}; std::stringstream start_date_str_stream("2023-01-31"); start_date_str_stream >> std::get_time(&tm_start_date, "%Y-%m-%d"); auto start_date_tp = std::chrono::system_clock::from_time_t(std::mktime(&tm_start_date)); std::cout << func::write_time(func::add_months(start_date_tp, 1)) << '\n'; return 0; }

alexl@PD70PNP:/mnt/Storage_SSD/C++_Projects/sunday_count$ ./sunday_count 2023-02-28