diff --git a/autotest/gdrivers/netcdf.py b/autotest/gdrivers/netcdf.py
index 0e046aa759ae..c26d620cbc04 100755
--- a/autotest/gdrivers/netcdf.py
+++ b/autotest/gdrivers/netcdf.py
@@ -6489,3 +6489,27 @@ def test_gdal_subdataset_bogus(bogus):
"""Test it doesn't crash"""
gdal.GetSubdatasetInfo(bogus)
+
+
+@gdaltest.enable_exceptions()
+def test_band_names_creation_option(tmp_path):
+
+ fname = tmp_path / "twobands.nc"
+
+ # 1 band, 2 names
+ with pytest.raises(Exception, match="but 2 names provided"):
+ gdal.GetDriverByName("NetCDF").Create(
+ fname, 1, 1, 1, options={"BAND_NAMES": "t2m,prate"}
+ )
+
+ # 2 bands, 2 names
+ with gdal.GetDriverByName("NetCDF").Create(
+ fname, 1, 1, 2, options={"BAND_NAMES": "t2m,prate"}
+ ):
+ pass
+
+ with gdal.Open(fname) as ds:
+ sds_names = [sds[0] for sds in ds.GetSubDatasets()]
+
+ assert gdal.GetSubdatasetInfo(sds_names[0]).GetSubdatasetComponent() == "t2m"
+ assert gdal.GetSubdatasetInfo(sds_names[1]).GetSubdatasetComponent() == "prate"
diff --git a/doc/source/drivers/raster/netcdf.rst b/doc/source/drivers/raster/netcdf.rst
index 49900cbf7fcb..fbe191d1d1d5 100644
--- a/doc/source/drivers/raster/netcdf.rst
+++ b/doc/source/drivers/raster/netcdf.rst
@@ -429,6 +429,12 @@ Creation Options
installations, but NC4 and NC4C are available if NetCDF was compiled
with NetCDF-4 (and HDF5) support.
+- .. co:: BAND_NAMES
+ :default: Band1,Band2,...
+ :since: 3.9.0
+
+ A comma-separated list of band names.
+
- .. co:: COMPRESS
:choices: NONE, DEFLATE
diff --git a/frmts/netcdf/netcdfdataset.cpp b/frmts/netcdf/netcdfdataset.cpp
index 68cf0c28cad4..067ca209634b 100644
--- a/frmts/netcdf/netcdfdataset.cpp
+++ b/frmts/netcdf/netcdfdataset.cpp
@@ -9156,7 +9156,6 @@ netCDFDataset *netCDFDataset::CreateLL(const char *pszFilename, int nXSize,
return poDS;
}
-
// Create the dataset.
CPLString osFilenameForNCCreate(pszFilename);
#if defined(_WIN32) && !defined(NETCDF_USES_UTF8)
@@ -9321,12 +9320,31 @@ GDALDataset *netCDFDataset::Create(const char *pszFilename, int nXSize,
: GDAL_DEFAULT_NCDF_CONVENTIONS);
}
+ CPLStringList aosBandNames;
+ if (const char *pszBandNames = aosOptions.FetchNameValue("BAND_NAMES"))
+ {
+ aosBandNames =
+ CSLTokenizeString2(pszBandNames, ",", CSLT_HONOURSTRINGS);
+
+ if (aosBandNames.Count() != nBandsIn)
+ {
+ CPLError(CE_Failure, CPLE_OpenFailed,
+ "Attempted to create netCDF with %d bands but %d names "
+ "provided in BAND_NAMES.",
+ nBandsIn, aosBandNames.Count());
+ return nullptr;
+ }
+ }
+
// Define bands.
for (int iBand = 1; iBand <= nBandsIn; iBand++)
{
- poDS->SetBand(
- iBand, new netCDFRasterBand(netCDFRasterBand::CONSTRUCTOR_CREATE(),
- poDS, eType, iBand, poDS->bSignedData));
+ const char *pszBandName =
+ aosBandNames.empty() ? nullptr : aosBandNames[iBand - 1];
+
+ poDS->SetBand(iBand, new netCDFRasterBand(
+ netCDFRasterBand::CONSTRUCTOR_CREATE(), poDS,
+ eType, iBand, poDS->bSignedData, pszBandName));
}
CPLDebug("GDAL_netCDF", "netCDFDataset::Create(%s, ...) done", pszFilename);
diff --git a/frmts/netcdf/netcdfdrivercore.cpp b/frmts/netcdf/netcdfdrivercore.cpp
index eb034cb4dbfb..9715a08e5160 100644
--- a/frmts/netcdf/netcdfdrivercore.cpp
+++ b/frmts/netcdf/netcdfdrivercore.cpp
@@ -429,6 +429,7 @@ void netCDFDriverSetCommonMetadata(GDALDriver *poDriver)
"description='Path to a XML configuration file (or content inlined)'/>"
" "
" "
+ " "
"");
poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");