diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h
index 809d795cbf2..c939b73c4c3 100644
--- a/libstdc++-v3/include/bits/chrono_io.h
+++ b/libstdc++-v3/include/bits/chrono_io.h
@@ -573,9 +573,9 @@ namespace __format
 
 	  auto __finalize = [this, &__spec, &__def] {
 	    using enum _ChronoParts;
-            _ChronoParts __checked 
+	    _ChronoParts __checked 
 	      = __spec._M_debug ? _YearMonthDay|_IndexedWeekday
-	                        : _Month|_Weekday;
+		                : _Month|_Weekday;
 	    // n.b. for calendar types __def._M_needed contains only parts
 	    // copied from the input, remaining ones are computed, and thus ok
 	    __spec._M_needs_ok_check 
@@ -694,7 +694,8 @@ namespace __format
 		  break;
 		case 'g':
 		case 'G':
-		  __needed = _LocalDays|_Weekday;
+		case 'V':
+		  __needed = _LocalDays|_Year|_DayOfYear|_Weekday;
 		  break;
 		case 'H':
 		case 'I':
@@ -742,9 +743,8 @@ namespace __format
 		  __allowed_mods = _Mod_O;
 		  break;
 		case 'U':
-		case 'V':
 		case 'W':
-		  __needed = _LocalDays|_Year|_DayOfYear|_Weekday;
+		  __needed = _DayOfYear|_Weekday;
 		  __allowed_mods = _Mod_O;
 		  break;
 		case 'x':
@@ -1148,7 +1148,8 @@ namespace __format
 		  break;
 		case 'g':
 		case 'G':
-		  __out = _M_g_G(__t, std::move(__out), __c == 'G');
+		case 'V':
+		  __out = _M_g_G_V(__t, std::move(__out), __c);
 		  break;
 		case 'H':
 		case 'I':
@@ -1190,9 +1191,8 @@ namespace __format
 		  __out = _M_u_w(__t._M_weekday, std::move(__out), __c);
 		  break;
 		case 'U':
-		case 'V':
 		case 'W':
-		  __out = _M_U_V_W(__t, std::move(__out), __c);
+		  __out = _M_U_W(__t, std::move(__out), __c);
 		  break;
 		case 'z':
 		  __out = _M_z(__t._M_zone_offset, std::move(__out), (bool)__mod);
@@ -1442,18 +1442,47 @@ namespace __format
 
       template<typename _OutIter>
 	_OutIter
-	_M_g_G(const _ChronoData<_CharT>& __t, _OutIter __out,
-	       bool __full) const
+	_M_g_G_V(const _ChronoData<_CharT>& __t, _OutIter __out,
+		_CharT __conv) const
 	{
-	  // %g last two decimal digits of the ISO week-based year.
-	  // %G ISO week-based year.
-	  using namespace chrono;
-	  auto __d = __t._M_ldays;
-	  // Move to nearest Thursday:
-	  __d -= (__t._M_weekday - Monday) - days(3);
+	  // %g  last two decimal digits of the ISO week-based year.
+	  // %G  ISO week-based year.
+	  // %V  ISO week-based week number as a decimal number.
+	  // %OV Locale's alternative numeric rep.
+	
 	  // ISO week-based year is the year that contains that Thursday:
-	  year __y = year_month_day(__d).year();
-	  return _M_C_y_Y(__y, std::move(__out), "yY"[__full]);
+	  // ISO week of __t is number of weeks since January 1 of the ISO year.
+	  
+	  using namespace chrono;
+	  const _CharT __yconv = "yY"[__conv == 'G'];
+	  // Offset of the nearest Thursday:
+	  const days __offset = (__t._M_weekday - Monday) - days(3);
+	  // Day of year of nearest Thursday:
+	  days __idoy = __t._M_day_of_year - __offset;
+	  if (__idoy > days(0) && __idoy <= days(365)) [[likely]]
+	    {
+	      // Nearest Thrusday is in the same year as __t._M_year
+	      if (__conv != 'V')
+		return _M_C_y_Y(__t._M_year, std::move(__out), __yconv);
+       
+	      const unsigned __wi = chrono::floor<weeks>(__idoy).count() + 1;
+	      return __format::__write(std::move(__out), _S_two_digits(__wi));
+	    }
+
+	  // Nearest Thursday as local days
+	  const local_days __ild = __t._M_ldays - __offset;
+	  // Nearest Thursday in previous year (__idoy <= 0), on a leap day
+	  // of same year, or later year (__idoy >= 366)
+	  const year __iyear = (__idoy <= days(0))
+			     ? __t._M_year - years(1)
+			     : year_month_day(__ild).year();
+	  if (__conv != 'V')
+	    return _M_C_y_Y(__iyear, std::move(__out), __yconv);
+ 
+	  // Recompute day of year from possibly updated year
+	  __idoy = __ild - local_days(__iyear/January/1);
+	  const unsigned __wi = chrono::floor<weeks>(__idoy).count() + 1;
+	  return __format::__write(std::move(__out), _S_two_digits(__wi));
 	}
 
       template<typename _OutIter>
@@ -1710,35 +1739,19 @@ namespace __format
 
       template<typename _OutIter>
 	_OutIter
-	_M_U_V_W(const _ChronoData<_CharT>& __t, _OutIter __out,
+	_M_U_W(const _ChronoData<_CharT>& __t, _OutIter __out,
 		 _CharT __conv) const
 	{
 	  // %U  Week number of the year as a decimal number, from first Sunday.
 	  // %OU Locale's alternative numeric rep.
-	  // %V  ISO week-based week number as a decimal number.
-	  // %OV Locale's alternative numeric rep.
 	  // %W  Week number of the year as a decimal number, from first Monday.
 	  // %OW Locale's alternative numeric rep.
+	  
 	  using namespace chrono;
-
-	  auto __d = __t._M_ldays;
-	  local_days __first; // First day of week 1.
-	  if (__conv == 'V') // W01 begins on Monday before first Thursday.
-	    {
-	      // Move to nearest Thursday:
-	      __d -= (__t._M_weekday - Monday) - days(3);
-	      // ISO week of __t is number of weeks since January 1 of the
-	      // same year as that nearest Thursday.
-	      __first = local_days(year_month_day(__d).year()/January/1);
-	    }
-	  else
-	    {
-	      const weekday __weekstart = __conv == 'U' ? Sunday : Monday;
-	      __first = local_days(__t._M_year/January/__weekstart[1]);
-	    }
-	  auto __weeks = chrono::floor<weeks>(__d - __first);
-	  __string_view __sv = _S_two_digits(__weeks.count() + 1);
-	  return __format::__write(std::move(__out), __sv);
+	  const weekday __weekstart = __conv == 'U' ? Sunday : Monday;
+	  const days __weekoffset = __t._M_weekday - __weekstart;
+	  auto __weeks = chrono::floor<weeks>(__t._M_day_of_year - __weekoffset);
+	  return __format::__write(std::move(__out), _S_two_digits(__weeks.count() + 1));
 	}
 
       template<typename _OutIter>
